home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / ck5a189s / ckuus5.c < prev    next >
C/C++ Source or Header  |  1993-07-05  |  105KB  |  3,951 lines

  1. #ifndef NOICP
  2.  
  3. /*  C K U U S 5 --  "User Interface" for Unix Kermit, part 5  */
  4.  
  5. /*
  6.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  7.   Columbia University Academic Information Systems, New York City.
  8.  
  9.   Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
  10.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  11.   sold for profit as a software product itself, nor may it be included in or
  12.   distributed with commercial products or otherwise distributed by commercial
  13.   concerns to their clients or customers without written permission of the
  14.   Office of Kermit Development and Distribution, Columbia University.  This
  15.   copyright notice must not be removed, altered, or obscured.
  16. */
  17.  
  18. /* Includes */
  19.  
  20. #include "ckcdeb.h"
  21. #include "ckcasc.h"
  22. #include "ckcker.h"
  23. #include "ckuusr.h"
  24. #include "ckcnet.h"
  25. #ifndef NOCSETS
  26. #include "ckcxla.h"
  27. #endif /* NOCSETS */
  28. #ifdef MAC
  29. #include "ckmasm.h"
  30. #endif /* MAC */
  31.  
  32. /* For formatted screens, "more?" prompting, etc. */
  33.  
  34. #define SCRNLEN 21            /* Screen length */
  35. #define SCRNWID 79            /* Screen width */
  36.  
  37. #ifdef FT18
  38. #define isxdigit(c) isdigit(c)
  39. #endif /* FT18 */
  40.  
  41. #ifdef MAC                /* Internal MAC file routines */
  42. #define feof mac_feof
  43. #define rewind mac_rewind
  44. #define fgets mac_fgets
  45. #define fopen mac_fopen
  46. #define fclose mac_fclose
  47.  
  48. int mac_feof();
  49. void mac_rewind();
  50. char *mac_fgets();
  51. FILE *mac_fopen();
  52. int mac_fclose();
  53. #endif /* MAC */
  54.  
  55. /* External variables */
  56.  
  57. extern int carrier, cdtimo, local, backgrd, bgset, sosi, suspend,
  58.   displa, binary, deblog, escape, xargs, flow, cmdmsk,
  59.   duplex, ckxech, pktlog, seslog, tralog, what,
  60.   keep, warn, tlevel, cwdf, nfuncs, unkcs, msgflg,
  61.   mdmtyp, zincnt, cmask, rcflag, success, xitsta, pflag, lf_opts, tnlm, tn_nlm,
  62.   xfrcan, xfrchr, xfrnum;
  63.  
  64. extern char *ccntab[];
  65.  
  66. #ifndef NOFRILLS
  67. extern int en_cwd, en_del, en_dir, en_fin, en_bye,
  68.   en_get, en_hos, en_sen, en_set, en_spa, en_typ, en_who;
  69. #endif /* NOFRILLS */
  70. extern long vernum;
  71. extern int srvtim, srvdis, inecho, insilence, nvars, verwho;
  72. extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav,
  73.  *cknetv, *clcmds;
  74. #ifdef OS2
  75. extern char *ckonetv;
  76. #endif /* OS2 */
  77. extern char *connv, *dialv, *loginv, *nvlook();
  78.  
  79. #ifndef NOSCRIPT
  80. extern int secho;
  81. #endif /* NOSCRIPT */
  82.  
  83. #ifndef NODIAL
  84. extern int nmdm;
  85. extern struct keytab mdmtab[];
  86. #endif /* NODIAL */
  87.  
  88. #ifdef NETCONN
  89. extern int tn_init, network, ttnproto;
  90. #endif /* NETCONN */
  91.  
  92. #ifdef OS2
  93. extern int tt_type, tt_arrow, tt_keypad, tt_wrap, tt_answer, tt_scrsize;
  94. #endif /* OS2 */
  95. extern int tt_crd;
  96.  
  97. #ifndef NOCSETS
  98. extern int language, nfilc, tcsr, tcsl;
  99. extern struct keytab fcstab[];
  100. extern struct csinfo fcsinfo[];
  101. #ifndef MAC
  102. extern struct keytab ttcstab[];
  103. #endif /* MAC */
  104. #endif /* NOCSETS */
  105.  
  106. extern int atcapr,
  107.   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
  108.   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; 
  109.  
  110. extern long speed;
  111.  
  112. extern char *DIRCMD, *PWDCMD, *DELCMD;
  113. #ifndef NOXMIT
  114. extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw;
  115. extern char xmitbuf[];
  116. #endif /* NOXMIT */
  117.  
  118. extern char **xargv, *versio, *ckxsys, *dftty, *cmarg, *lp;
  119.  
  120. #ifdef DCMDBUF
  121. extern char *cmdbuf, *atmbuf;        /* Command buffers */
  122. #ifndef NOSPL
  123. extern char *savbuf;            /* Command buffers */
  124. #endif /* NOSPL */
  125. #else
  126. extern char cmdbuf[], atmbuf[];        /* Command buffers */
  127. #ifndef NOSPL
  128. extern char savbuf[];            /* Command buffers */
  129. #endif /* NOSPL */
  130. #endif /* DCMDBUF */
  131.  
  132. extern char toktab[], ttname[], psave[];
  133. extern CHAR sstate;
  134. extern int cmflgs, techo, repars, ncmd;
  135. extern struct keytab cmdtab[];
  136.  
  137. #ifndef MAC
  138. #ifndef NOSETKEY
  139. KEY *keymap;
  140. MACRO *macrotab;
  141. #endif /* NOSETKEY */
  142. #endif /* MAC */
  143.  
  144. #ifndef NOSPL
  145. extern struct mtab *mactab;
  146. extern struct keytab vartab[], fnctab[];
  147. extern int cmdlvl, maclvl, nmac, mecho;
  148. #endif /* NOSPL */
  149.  
  150. FILE *tfile[MAXTAKE];            /* TAKE file stack */
  151. char *tfnam[MAXTAKE];
  152.  
  153. #ifndef NOSPL
  154. /* Local declarations */
  155.  
  156. int nulcmd = 0;            /* Flag for next cmd to be ignored */
  157.  
  158. /* Definitions for predefined macros */
  159.  
  160. /* First, the single-line macros, installed with addmac()... */
  161.  
  162. /* IBM-LINEMODE macro */
  163. char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none";
  164.  
  165. /* FATAL macro */
  166. char *m_fat = "if def \\%1 echo \\%1, if not = \\v(local) 0 hangup, stop 1";
  167.  
  168. /* Now the multiline macros, defined with addmmac()... */
  169.  
  170. /* FOR macro */
  171. char *for_def[] = { "_assign _for\\v(cmdlevel) { _getargs,",
  172. "define \\\\\\%1 \\%2,:top,if \\%5 \\\\\\%1 \\%3 goto bot,",
  173. "\\%6,:inc,incr \\\\\\%1 \\%4,goto top,:bot,_putargs},",
  174. "def break goto bot, def continue goto inc,",
  175. "do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)",
  176. ""};
  177.  
  178. /* WHILE macro */
  179. char *whil_def[] = { "_assign _whi\\v(cmdlevel) {_getargs,",
  180. ":inc,\\%1,\\%2,goto inc,:bot,_putargs},",
  181. "_def break goto bot, _def continue goto inc,",
  182. "do _whi\\v(cmdlevel),_assign _whi\\v(cmdlevel)",
  183. ""};
  184.  
  185. /* XIF macro */
  186. char *xif_def[] = {
  187. "_assign _if\\v(cmdlevel) {_getargs,\\%1,_putargs},",
  188. "do _if\\v(cmdlevel),_assign _if\\v(cmdlevel)",
  189. ""};
  190.  
  191. /*
  192.   Variables declared here for use by other ckuus*.c modules.
  193.   Space is allocated here to save room in ckuusr.c.
  194. */
  195. #ifdef DCMDBUF
  196. struct cmdptr *cmdstk;
  197. int *ifcmd, *count, *iftest, *intime, *inpcas, *takerr, *merror;
  198. #else
  199. struct cmdptr cmdstk[CMDSTKL];
  200. int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL], intime[CMDSTKL],
  201.   inpcas[CMDSTKL], takerr[CMDSTKL], merror[CMDSTKL];
  202. #endif /* DCMDBUF */
  203.  
  204. char *m_arg[MACLEVEL][NARGS];
  205. char *g_var[GVARS], *macp[MACLEVEL], *mrval[MACLEVEL];
  206. int macargc[MACLEVEL];
  207. char *macx[MACLEVEL];
  208. extern char varnam[];
  209.  
  210. char **a_ptr[27];            /* Array pointers, for arrays a-z */
  211. int a_dim[27];                /* Dimensions for each array */
  212.  
  213. char inpbuf[INPBUFSIZ] = { NUL };    /* Buffer for INPUT and REINPUT */
  214. char inpbufa[2] = { NUL, NUL };        /* Null terminators for INPUT buffer */
  215. char inchar[2] = { NUL, NUL };        /* Last character that was INPUT */
  216. int  incount = 0;            /* INPUT character count */
  217. int pacing = 0;                /* OUTPUT pacing */
  218.  
  219. char lblbuf[LBLSIZ];            /* Buffer for labels */
  220. #else
  221. int takerr[MAXTAKE];
  222. #endif /* NOSPL */
  223.  
  224. #ifdef DCMDBUF
  225. char *line;                /* Character buffer for anything */
  226. char *tmpbuf;
  227. #else
  228. char line[LINBUFSIZ];
  229. char tmpbuf[TMPBUFSIZ];            /* Temporary buffer */
  230. #endif /* DCMDBUF */
  231. char *tp;                /* Temporary buffer pointer */
  232.  
  233. #ifdef CK_CURSES
  234. #ifndef TRMBUFL
  235. #define TRMBUFL 1024
  236. #endif /* TRMBUFL */
  237. #ifdef DCMDBUF
  238. char *trmbuf;                /* Character buffer for termcap */
  239. #else
  240. char trmbuf[TRMBUFL];
  241. #endif /* DCMDBUF */
  242. #endif /* CK_CURSES */
  243.  
  244. extern char pktfil[],
  245. #ifdef DEBUG
  246.   debfil[],
  247. #endif /* DEBUG */
  248. #ifdef TLOG
  249.   trafil[],
  250. #endif /* TLOG */
  251.   sesfil[],
  252.   cmdstr[];
  253. #ifndef NOFRILLS
  254. extern int rmailf, rprintf;        /* REMOTE MAIL & PRINT items */
  255. extern char optbuf[];
  256. #endif /* NOFRILLS */
  257.  
  258. char *homdir = "";            /* Pointer to home directory string */
  259.  
  260. char numbuf[20];            /* Buffer for numeric strings. */
  261. char kermrc[100];            /* Name of initialization file */
  262. int noinit = 0;                /* Flag for skipping init file */
  263.  
  264. #ifndef NOSPL
  265. _PROTOTYP( static long expon, (long, long) );
  266. _PROTOTYP( static long gcd, (long, long) );
  267. _PROTOTYP( static long fact, (long) );
  268. int            /* Initialize macro data structures. */
  269. macini() {        /* Allocate mactab and preset the first element. */
  270.     if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX)))
  271.       return(-1);
  272.     mactab[0].kwd = NULL;
  273.     mactab[0].mval = NULL;
  274.     mactab[0].flgs = 0;
  275.     return(0);
  276. }
  277. #endif /* NOSPL */
  278.  
  279. /*  C M D I N I  --  Initialize the interactive command parser  */
  280.  
  281. VOID
  282. cmdini() {
  283.     int i, x, y, z;
  284. #ifndef NOSPL
  285. /*
  286.   On stack in case of recursion!
  287. */
  288.     char vnambuf[VNAML];        /* Buffer for variable names */
  289. #endif /* NOSPL */
  290.  
  291. #ifndef MAC
  292. #ifndef NOSETKEY            /* Allocate & initialize the keymap */
  293.     if (!(keymap = (KEY *) malloc(sizeof(KEY)*KMSIZE)))
  294.       fatal("cmdini: no memory for keymap");
  295.     if (!(macrotab = (MACRO *) malloc(sizeof(MACRO)*KMSIZE)))
  296.       fatal("cmdini: no memory for macrotab");
  297.     for ( i = 0; i < KMSIZE; i++ ) {
  298.     keymap[i] = i;
  299.     macrotab[i] = NULL;
  300.     }
  301. #ifdef OS2
  302.     keymapinit();
  303. #endif /* OS2 */
  304. #endif /* NOSETKEY */
  305. #endif /* MAC */
  306.  
  307. #ifdef DCMDBUF
  308.     if (cmsetup() < 0) fatal("Can't allocate command buffers!");
  309. #ifndef NOSPL
  310.     if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL)))
  311.     fatal("cmdini: no memory for cmdstk");
  312.     if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL)))
  313.     fatal("cmdini: no memory for ifcmd");
  314.     if (!(count = (int *) malloc(sizeof(int)*CMDSTKL)))
  315.     fatal("cmdini: no memory for count");
  316.     if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL)))
  317.     fatal("cmdini: no memory for iftest");
  318.     if (!(intime = (int *) malloc(sizeof(int)*CMDSTKL)))
  319.     fatal("cmdini: no memory for intime");
  320.     if (!(inpcas = (int *) malloc(sizeof(int)*CMDSTKL)))
  321.     fatal("cmdini: no memory for inpcas");
  322.     if (!(takerr = (int *) malloc(sizeof(int)*CMDSTKL)))
  323.     fatal("cmdini: no memory for takerr");
  324.     if (!(merror = (int *) malloc(sizeof(int)*CMDSTKL)))
  325.     fatal("cmdini: no memory for merror");
  326. #endif /* NOSPL */
  327. #ifdef CK_CURSES
  328. /*
  329.   Termcap buffer for fullscreen display, UNIX only.  VMS does it another way.
  330.   The fullscreen display is not supported on AOS/VS or OS-9, etc, yet, and
  331.   the Mac has its own built-in fullscreen display.
  332. */
  333. #ifdef UNIX
  334.     if (!(trmbuf = malloc(TRMBUFL+1)))
  335.     fatal("cmdini: no memory for termcap buffer");
  336. #endif /* UNIX */
  337. #endif /* CK_CURSES */
  338.     if (!(line = malloc(LINBUFSIZ)))
  339.     fatal("cmdini: no memory for line");
  340.     if (!(tmpbuf = malloc(LINBUFSIZ)))
  341.     fatal("cmdini: no memory for tmpbuf");
  342. #endif /* DCMDBUF */
  343.  
  344. #ifndef NOSPL
  345.     if (macini() < 0)
  346.       fatal("Can't allocate macro buffers!");
  347.  
  348.     ifcmd[0] = 0;        /* Command-level related variables. */
  349.     iftest[0] = 0;        /* initialize variables at top level */
  350.     count[0] = 0;        /* of stack... */
  351.     intime[0] = 0;
  352.     inpcas[0] = 0;
  353.     takerr[0] = 0;
  354.     merror[0] = 0;
  355. #endif /* NOSPL */
  356.  
  357. #ifdef AMIGA
  358.     if (tlevel < 0)    
  359.       concb(escape);
  360. #endif /* AMIGA */
  361.  
  362. #ifndef NOSPL
  363.     cmdlvl = 0;                /* Start at command level 0 */
  364.     cmdstk[cmdlvl].src = CMD_KB;
  365.     cmdstk[cmdlvl].lvl = 0;
  366. #endif /* NOSPL */
  367.  
  368.     tlevel = -1;            /* Take file level = keyboard */
  369.     for (i = 0; i < MAXTAKE; i++)    /* Initialize command file names */
  370.       tfnam[i] = NULL;
  371.  
  372. #ifdef MAC 
  373.     cmsetp("Mac-Kermit>");        /* Set default prompt */
  374. #else
  375.     cmsetp("C-Kermit>");        /* Set default prompt */
  376. #endif /* MAC */
  377.  
  378. #ifndef NOSPL
  379.     initmac();                /* Initialize macro table */
  380. /* Add one-line macros */
  381.     addmac("ibm-linemode",m_ibm);    /* Add built-in macros. */
  382.     addmac("fatal",m_fat);        /* FATAL macro. */
  383. /* Add multiline macros */
  384.     addmmac("_forx",for_def);        /* FOR macro. */
  385.     addmmac("_xif",xif_def);        /* XIF macro. */
  386.     addmmac("_while",whil_def);        /* WHILE macro. */
  387. /* Fill in command line argument vector */
  388.     sprintf(vnambuf,"\\&@[%d]",xargs);     /* Command line argument vector */
  389.     y = arraynam(vnambuf,&x,&z);    /* goes in array \&@[] */
  390.     if (y > -1) {
  391.     dclarray((char)x,z);        /* Declare the array */
  392.     for (i = 0; i < xargs; i++) {    /* Fill it */
  393.         sprintf(vnambuf,"\\&@[%d]",i);
  394.         addmac(vnambuf,xargv[i]);
  395.     }
  396.     }
  397.     *vnambuf = NUL;
  398. #endif /* NOSPL */
  399.  
  400. /* Get our home directory now.  This needed in lots of places. */
  401.  
  402.     homdir = zhome();
  403.  
  404. /* If skipping init file ('-Y' on Kermit command line), return now. */
  405.  
  406.     if (noinit) return;
  407.  
  408. #ifdef OS2
  409. /*
  410.   The -y init file must be fully specified or in the current directory.
  411.   KERMRC is looked for via INIT, PATH and DPATH in that order.  Finally, our
  412.   own executable file path is taken and the .EXE suffix is replaced by .INI
  413.   and this is tried as initialization file.
  414. */
  415.     if (rcflag) {
  416.     strcpy(line, kermrc);
  417.     } else {
  418.     _searchenv(kermrc,"INIT",line);
  419.     if (line[0] == 0)
  420.       _searchenv(kermrc,"PATH",line);
  421.     if (line[0] == 0)
  422.       _searchenv(kermrc,"DPATH",line);
  423.     if (line[0] == 0) {
  424.         char *pgmptr = GetLoadPath();
  425.         if (pgmptr) {
  426.           lp = strrchr(pgmptr, '.');
  427.           strncpy(line, pgmptr, lp - pgmptr);
  428.           strcpy(line + (lp - pgmptr), ".ini");
  429.         }
  430.     }
  431.     }
  432.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  433.         tlevel = 0;
  434.     if (tfnam[tlevel] = malloc(strlen(line)+1))
  435.       strcpy(tfnam[tlevel],line);
  436. #ifndef NOSPL
  437.     cmdlvl++;
  438.     cmdstk[cmdlvl].src = CMD_TF;
  439.     cmdstk[cmdlvl].lvl = tlevel;
  440.     ifcmd[cmdlvl] = 0;
  441.     iftest[cmdlvl] = 0;
  442.     count[cmdlvl] =  count[cmdlvl-1]; /* Inherit from previous level */
  443.     intime[cmdlvl] = intime[cmdlvl-1];
  444.     inpcas[cmdlvl] = inpcas[cmdlvl-1];
  445.     takerr[cmdlvl] = takerr[cmdlvl-1];
  446.     merror[cmdlvl] = merror[cmdlvl-1];
  447. #endif /* NOSPL */
  448.         debug(F110,"init file",line,0);
  449.     } else {
  450.         debug(F100,"no init file","",0);
  451.     }
  452. #else /* not OS2 */
  453.     lp = line;
  454.     lp[0] = '\0';
  455. #ifdef GEMDOS
  456.     zkermini(line,rcflag, kermrc);
  457. #else
  458. #ifdef VMS
  459.     zkermini(line,LINBUFSIZ,kermrc);
  460. #else /* not VMS */
  461.     if (rcflag) {            /* If init file name from cmd line */
  462.     strcpy(lp,kermrc);        /* use it */
  463.     } else {                /* otherwise */
  464.     if (homdir) {            /* look in home directory for it */
  465.         strcpy(lp,homdir);
  466.         if (lp[0] == '/') strcat(lp,"/");
  467.     }
  468.     strcat(lp,kermrc);        /* and use the default name */
  469.     }
  470. #endif /* VMS */
  471. #endif /* GEMDOS */
  472.  
  473. #ifdef AMIGA
  474.     reqoff();                /* disable requestors */
  475. #endif /* AMIGA */
  476.  
  477.     debug(F110,"ini file is",line,0);
  478.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  479.     tlevel = 0;
  480.     if (tfnam[tlevel] = malloc(strlen(line)+1))
  481.       strcpy(tfnam[tlevel],line);
  482. #ifndef NOSPL
  483.     cmdlvl++;
  484.     ifcmd[cmdlvl] = 0;
  485.     iftest[cmdlvl] = 0;
  486.     count[cmdlvl] =  count[cmdlvl-1]; /* Inherit from previous level */
  487.     intime[cmdlvl] = intime[cmdlvl-1];
  488.     inpcas[cmdlvl] = inpcas[cmdlvl-1];
  489.     takerr[cmdlvl] = takerr[cmdlvl-1];
  490.     merror[cmdlvl] = merror[cmdlvl-1];
  491.     debug(F101,"open ok","",cmdlvl);
  492.     cmdstk[cmdlvl].src = CMD_TF;
  493.     cmdstk[cmdlvl].lvl = tlevel;
  494. #endif /* NOSPL */
  495.     debug(F110,"init file",line,0);
  496.     }
  497.     if (homdir && (tlevel < 0)) {
  498.         strcpy(lp,kermrc);
  499.     if ((tfile[0] = fopen(line,"r")) != NULL) {
  500.         tlevel = 0;
  501.     if (tfnam[tlevel] = malloc(strlen(line)+1))
  502.       strcpy(tfnam[tlevel],line);
  503. #ifndef NOSPL
  504.         cmdlvl++;
  505.         cmdstk[cmdlvl].src = CMD_TF;
  506.         cmdstk[cmdlvl].lvl = tlevel;
  507.         ifcmd[cmdlvl] = 0;
  508.         iftest[cmdlvl] = 0;
  509.         count[cmdlvl] =  count[cmdlvl-1]; /* Inherit from previous level */
  510.         intime[cmdlvl] = intime[cmdlvl-1];
  511.         inpcas[cmdlvl] = inpcas[cmdlvl-1];
  512.         takerr[cmdlvl] = takerr[cmdlvl-1];
  513.         merror[cmdlvl] = merror[cmdlvl-1];
  514. #endif /* NOSPL */
  515.     }
  516.     }
  517. #endif /* OS2 */
  518. #ifdef AMIGA
  519.     reqpop();                /* Restore requestors */
  520. #endif /* AMIGA */
  521. }
  522.  
  523. #ifndef NOSPL
  524. /*
  525.   G E T N C M
  526.  
  527.   Get next command from current macro definition.
  528.  
  529.   Moved to a separate routine in edit 181 to allow multiline GET
  530.   to work when issued in a macro.
  531.  
  532.   Command is copied into string pointed to by argument s, max length n.
  533.   Returns:
  534.    0 if a string was copied, -1 if there was no string to copy.
  535. */
  536. int
  537. getncm(s,n) char *s; int n; {
  538.     int y, kp = 0, pp = 0;
  539.     char *s2;
  540.     
  541.     s2 = s;
  542.     *s = NUL;                /* Copy next cmd to command buffer. */
  543.     
  544.     debug(F111,"getncm",s,n);
  545.  
  546.     for (y = 0;
  547.       macp[maclvl] && *macp[maclvl] && y < n;
  548.      y++, s++, macp[maclvl]++) {
  549.     
  550.     *s = *macp[maclvl];        /* Get next character */
  551.     debug(F000,"char","",*s);
  552. /*
  553.   Allow braces around macro definition to prevent commas from being turned to
  554.   end-of-lines and also treat any commas within parens as text so that
  555.   multiple-argument functions won't cause the command to break prematurely.
  556. */
  557.     if (*s == '{') kp++;        /* Count braces */
  558.     if (*s == '}') kp--;
  559.     if (*s == '(') pp++;        /* Count parentheses. */
  560.     if (*s == ')') pp--;
  561.     if (*s == ',' && pp <= 0 && kp <= 0) {
  562.         macp[maclvl]++;
  563.         debug(F110,"next cmd",s,0);
  564.         kp = pp = 0;
  565.         break;
  566.     }
  567.     }                    /* Reached end. */
  568.     if (*s2 == NUL) {            /* If nothing was copied, */
  569.     debug(F100,"getncm eom","",0);
  570.     popclvl();            /* pop command level. */
  571.     return(-1);
  572.     } else {                /* otherwise, tack CR onto end */
  573.     *s++ = CR;
  574.     *s = '\0';
  575.     if (mecho && pflag)
  576.       printf("%s\n",s2);
  577.     debug(F101,"getncm returns ptr to",s2,0);
  578.     }
  579.     return(0);
  580. }
  581. #endif /* NOSPL */
  582.  
  583. /*
  584.   G E T N C T
  585.  
  586.   Get next command from current TAKE file.
  587.  
  588.   Moved to a separate routine in edit 181 to allow multiline GET
  589.   to work when issued in a macro.
  590.  
  591.   Command is copied into string pointed to by argument s, max length n.
  592.   Returns:
  593.    0 if a string was copied,
  594.   -1 on EOF,
  595.   -2 on malloc failure
  596.   -3 if line not properly terminated
  597. */
  598. int
  599. getnct(s,n) char *s; int n; {
  600.     int i, j;
  601.     char c, *s2, *lp, *lp2;
  602.  
  603.     s2 = s;                /* Remember original pointer */
  604.  
  605.     debug(F101,"getnct","",n);
  606.     if (!(lp2 = (char *) malloc(n+1))) { /* Get a temporary buffer */
  607.     debug(F101,"getnct malloc failure","",0);
  608.     return(-2);
  609.     }
  610.     while (1) {                /* Loop to read lines from file */
  611.     
  612.     if (fgets(lp2,n,tfile[tlevel]) == NULL) { /* EOF */
  613.         free(lp2);            /* Free temporary storage */
  614.         *s = NUL;            /* Make destination be empty */
  615.         return(-1);            /* Return failure code */
  616.     }
  617.     if (techo && pflag)        /* If TAKE ECHO ON, */
  618.       printf("%s",lp2);        /* echo it. */
  619.  
  620.     lp = lp2;            /* Make a working pointer */
  621.  
  622. /* Trim trailing whitespace */
  623.  
  624.     j = strlen(lp2) - 1;        /* Position of line terminator */
  625.     debug(F111,"Line from TAKE file",lp2,j); /* Got a line */
  626.     if (j < 0) j = 0;
  627.     c = lp2[j];            /* Value of line terminator */
  628.     debug(F101,"getnct nl","",c);
  629.     if (c < LF || c > CR) {        /* It's not a terminator */
  630.         debug(F111,"getnct bad line",lp2,c);
  631.         if (feof(tfile[tlevel]) && j > 0 && j < n) {
  632.         printf("Warning: Last line of TAKE file lacks terminator\n");
  633.         c = lp2[++j] = '\n';
  634.         } else { free(lp2); return(-3); }
  635.     }
  636.     for (i = j - 1; i > -1; i--)    /* Back up over spaces and tabs */
  637.       if (lp2[i] != SP && lp2[i] != HT && lp2[i] != NUL)
  638.         break;
  639.     debug(F101,"getnct i","",i);
  640.     lp2[i+1] = c;            /* Move after last nonblank char */
  641.     lp2[i+2] = NUL;            /* Terminate the string */
  642.     debug(F110,"getnct lp2",lp2,0);
  643.     while (*s++ = *lp++) {        /* Copy result to target buffer */
  644.         if (--n < 2) {
  645.         printf("?Command too long, maximum length: %d.\n",CMDBL);
  646.         free(lp2);
  647.         return(dostop());
  648.         }
  649.  
  650. /* Check for trailing comment, " ;" or " #" */
  651.  
  652.         if ((s > s2 + 1) &&
  653.         (*(s-1) == ';' || *(s-1) == '#') &&
  654.         (*(s-2) == SP  || *(s-2) == HT)) {
  655.         debug(F100,"Trailing comment","",0);
  656.         s -= 2;            /* Got one, back up buffer pointer */
  657.         n += 2;            /* and adjust free space count. */
  658.         while ((s >= s2)    /* Trim whitespace again. */
  659.                && (*s == SP || *s == HT))
  660.           s--, n++;
  661.         s++;            /* Point after last character */
  662.         *s++ = c;        /* Put back line terminator */
  663.         *s++ = NUL;        /* and string terminator */
  664.         n -= 3;            /* Adjust free count */
  665.         debug(F110,"Comment trimmed & terminated",s2,0);
  666.         break;
  667.         }
  668.     }
  669.  
  670. /* Check whether this line is continued */
  671.  
  672.     if (s > s2 + 2) {
  673.         debug(F000,"Last char in line","",*(s-3));
  674.         if (*(s - 3) != CMDQ && *(s - 3) != '-') /* Line continued? */
  675.           break;            /* No, done. */
  676.         s -= 3;            /* No, back up pointer */
  677.         debug(F100,"Line is continued","",0); /* and continue */
  678.     } else break;
  679.     }
  680.     untab(s2);                /* Done, convert tabs to spaces */
  681.     free(lp2);                /* Free temporary storage */
  682.     return(0);                /* Return success */
  683. }
  684.  
  685. /*  P A R S E R  --  Top-level interactive command parser.  */
  686.  
  687. /*
  688.   Call with:
  689.     m = 0 for normal behavior: keep parsing and executing commands
  690.           until an action command is parsed, then return with a
  691.           Kermit start-state as the value of this function.
  692.     m = 1 to parse only one command, can also be used to call parser()
  693.           recursively.
  694.     m = 2 to read but do not execute one command.
  695.   In all cases, parser() returns:
  696.     0     if no Kermit protocol action required
  697.     > 0   with a Kermit protocol start-state.
  698.     < 0   upon error.
  699. */
  700. int
  701. parser(m) int m; {
  702.     int tfcode, xx, yy, zz;        /* Workers */
  703.  
  704. #ifndef NOSPL
  705.     int inlevel;            /* Level we were called at */
  706. #endif /* NOSPL */
  707.     char *cbp;                /* Command buffer pointer */
  708. #ifdef MAC
  709.     extern char *lfiles;        /* Fake extern cast */
  710. #endif /* MAC */
  711.  
  712. #ifdef AMIGA
  713.     reqres();            /* restore AmigaDOS requestors */
  714. #endif /* AMIGA */
  715.  
  716.     what = W_COMMAND;        /* Now we're parsing commands. */
  717. #ifndef NOSPL
  718.     if (cmdlvl == 0)        /* If at top (interactive) level, */
  719. #else
  720.     if (tlevel < 0)
  721. #endif /* NOSPL */
  722.       concb((char)escape);    /* put console in cbreak mode. */
  723.  
  724. #ifndef NOSPL
  725.     inlevel = cmdlvl;        /* Current macro level */
  726.     debug(F101,"&parser entry maclvl","",maclvl);
  727.     debug(F101,"&parser entry inlevel","",inlevel);
  728.     debug(F101,"&parser entry tlevel","",tlevel);
  729.     debug(F101,"&parser entry cmdlvl","",cmdlvl);
  730.     debug(F101,"&parser entry m","",m);
  731. #endif /* NOSPL */
  732.  
  733. /*
  734.   sstate becomes nonzero when a command has been parsed that requires some
  735.   action from the protocol module.  Any non-protocol actions, such as local
  736.   directory listing or terminal emulation, are invoked directly from below.
  737. */
  738. #ifdef COMMENT
  739.     if (local && pflag)            /* Just returned from connect? */
  740.       printf("\n");
  741. #endif /* COMMENT */
  742.     sstate = 0;                /* Start with no start state. */
  743. #ifndef NOFRILLS
  744.     rmailf = rprintf = 0;        /* MAIL and PRINT modifiers for SEND */
  745.     *optbuf = NUL;            /* MAIL and PRINT options */
  746. #endif /* NOFRILLS */
  747.     while (sstate == 0) {        /* Parse cmds until action requested */
  748.     debug(F100,"top of parse loop","",0);
  749.  
  750.     /* Take requested action if there was an error in the previous command */
  751.  
  752. #ifndef MAC
  753.     conint(trap,stptrap);        /* In case we were just fg'd */
  754.     bgchk();            /* Check background status */
  755. #endif /* MAC */
  756.  
  757.     debug(F101,"tlevel","",tlevel);
  758. #ifndef NOSPL                /* In case we just reached top level */
  759.     debug(F101,"cmdlvl","",cmdlvl);
  760.     if (cmdlvl == 0) concb((char)escape);
  761. #else
  762.     if (tlevel < 0) concb((char)escape);
  763. #endif /* NOSPL */
  764.  
  765. #ifndef NOSPL
  766.     if (success == 0) {
  767.         if (cmdstk[cmdlvl].src == CMD_TF && takerr[cmdlvl]) {
  768.         printf("Command file terminated by error.\n");
  769.         popclvl();
  770.         if (cmdlvl == 0) return(0);
  771.         }
  772.         if (cmdstk[cmdlvl].src == CMD_MD && merror[cmdlvl]) {
  773.         printf("Command error: macro terminated.\n");
  774.         popclvl();
  775.         if (m && (cmdlvl < inlevel))
  776.           return((int) sstate);
  777.         }
  778.     }
  779.  
  780.     nulcmd = (m == 2);
  781. #else
  782.     if (success == 0 && tlevel > -1 && takerr[tlevel]) {
  783.         printf("Command file terminated by error.\n");
  784.         popclvl();
  785.         cmini(ckxech);        /* Clear the cmd buffer. */
  786.         if (tlevel < 0)         /* Just popped out of cmd files? */
  787.           return(0);        /* End of init file or whatever. */
  788.     }
  789. #endif /* NOSPL */
  790.  
  791. #ifdef MAC
  792.     /* Check for TAKE initiated by menu. */
  793.     if ((tlevel == -1) && lfiles)
  794.         startlfile();
  795. #endif /* MAC */
  796.  
  797.         /* If in TAKE file, check for EOF */
  798. #ifndef NOSPL
  799. #ifdef MAC
  800.     if
  801. #else
  802.     while
  803. #endif /* MAC */
  804.       ((cmdstk[cmdlvl].src == CMD_TF)  /* If end of take file */
  805.            && (tlevel > -1)
  806.            && feof(tfile[tlevel])) {
  807.         popclvl();            /* pop command level */
  808.         cmini(ckxech);        /* and clear the cmd buffer. */
  809.         if (cmdlvl == 0)        /* Just popped out of all cmd files? */
  810.           return(0);        /* End of init file or whatever. */
  811.      }
  812. #ifdef MAC
  813.     miniparser(1);
  814.     if (sstate == 'a') {        /* if cmd-. cancel */
  815.         debug(F100, "parser: cancel take due to sstate", "", sstate);
  816.         sstate = '\0';
  817.         dostop();
  818.         return(0);            /* End of init file or whatever. */
  819.     }
  820. #endif /*  MAC */
  821.  
  822. #else /* NOSPL */
  823.     if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */
  824.         popclvl();            /* Pop up one level. */
  825.         cmini(ckxech);        /* and clear the cmd buffer. */
  826.         if (tlevel < 0)         /* Just popped out of cmd files? */
  827.           return(0);        /* End of init file or whatever. */
  828.      }
  829. #endif /* NOSPL */
  830.  
  831. #ifndef NOSPL
  832.         if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
  833.         debug(F100,"parser macro","",0);
  834.         maclvl = cmdstk[cmdlvl].lvl; /* Get current level */
  835.         debug(F101,"parser maclvl","",maclvl);
  836.         cbp = cmdbuf;        /* Copy next cmd to command buffer. */
  837.         *cbp = NUL;
  838.         if (*savbuf) {        /* In case then-part of 'if' command */
  839.         strcpy(cbp,savbuf);    /* was saved, restore it. */
  840.         *savbuf = '\0';
  841.         } else {            /* Else get next cmd from macro def */
  842.         if (getncm(cbp,CMDBL) < 0) {
  843.             if (m && (cmdlvl < inlevel))
  844.               return((int) sstate);
  845.             else /* if (!m) */ continue;
  846.         }
  847.         }
  848.         debug(F110,"cmdbuf from macro",cmdbuf,0);
  849.  
  850.     } else if (cmdstk[cmdlvl].src == CMD_TF)
  851. #else
  852.       if (tlevel > -1)  
  853. #endif /* NOSPL */
  854.       {
  855. #ifndef NOSPL
  856.         if (*savbuf) {        /* In case THEN-part of IF command */
  857.         strcpy(cmdbuf,savbuf);    /* was saved, restore it. */
  858.         *savbuf = '\0';
  859.         } else
  860. #endif /* NOSPL */
  861.  
  862.           /* Get next line from TAKE file */
  863.  
  864.           if ((tfcode = getnct(cmdbuf,CMDBL)) < 0) {
  865.           if (tfcode < -1) {    /* Error */
  866.               printf("?Error in TAKE command file: %s\n",
  867.                  (tfcode == -2) ? "Memory allocation failure" :
  868.                  "Line too long or contains NUL characters"
  869.                  );
  870.               popclvl();
  871.           }
  872.           continue;        /* -1 means EOF */
  873.           }        
  874.  
  875.         /* If interactive, get next command from user. */
  876.  
  877.     } else {            /* User types it in. */
  878.         if (pflag) prompt(xxstring);
  879.         cmini(ckxech);
  880.         }
  881.  
  882.         /* Now know where next command is coming from. Parse and execute it. */
  883.  
  884.     repars = 1;            /* 1 = command needs parsing */
  885.     displa = 0;            /* Assume no file transfer display */
  886.  
  887.     while (repars) {        /* Parse this cmd until entered. */
  888.         debug(F101,"parser top of while loop","",0);
  889.         cmres();            /* Reset buffer pointers. */
  890.         xx = cmkey2(cmdtab,ncmd,"Command","",toktab,xxstring);
  891.         debug(F101,"top-level cmkey2","",xx);
  892.         if (xx == -5) {
  893.         yy = chktok(toktab);
  894.         debug(F101,"top-level cmkey token","",yy);
  895.         ungword();
  896.         switch (yy) {
  897. #ifndef NOPUSH
  898.           case '!': xx = XXSHE; break; /* Shell escape */
  899. #endif /* NOPUSH */
  900.           case '#': xx = XXCOM; break; /* Comment */
  901.           case ';': xx = XXCOM; break; /* Comment */
  902. #ifndef NOSPL
  903.           case ':': xx = XXLBL; break; /* GOTO label */
  904. #endif /* NOSPL */
  905. #ifndef NOPUSH
  906.                   case '@': xx = XXSHE; break; /* Shell (DCL) escape */
  907. #endif /* NOPUSH */
  908.           default: 
  909.             printf("\n?Invalid - %s\n",cmdbuf);
  910.             xx = -2;
  911.         }
  912.         }
  913.  
  914. #ifndef NOSPL
  915.             /* Special handling for IF..ELSE */
  916.  
  917.         if (ifcmd[cmdlvl])        /* Count stmts after IF */
  918.           ifcmd[cmdlvl]++;
  919.         if (ifcmd[cmdlvl] > 2 && xx != XXELS && xx != XXCOM)
  920.           ifcmd[cmdlvl] = 0;
  921.  
  922.         /* Execute the command and take action based on return code. */
  923.  
  924.         if (nulcmd) {        /* Ignoring this command? */
  925.         xx = XXCOM;        /* Make this command a comment. */
  926.         }
  927. #endif /* NOSPL */
  928.  
  929.         zz = docmd(xx);    /* Parse rest of command & execute. */
  930.         debug(F101,"docmd returns","",zz);
  931. #ifdef MAC
  932.         if (tlevel > -1) {
  933.         if (sstate == 'a') {    /* if cmd-. cancel */
  934.             debug(F110, "parser: cancel take, sstate:", "a", 0);
  935.             sstate = '\0';
  936.             dostop();
  937.             return(0);        /* End of init file or whatever. */
  938.         }
  939.         }
  940. #endif /* MAC */
  941.         switch (zz) {
  942.         case -4:        /* EOF (e.g. on redirected stdin) */
  943.             doexit(GOOD_EXIT,xitsta); /* ...exit successfully */
  944.             case -1:        /* Reparse needed */
  945.             repars = 1;        /* Just set reparse flag and  */
  946.             continue;
  947.         case -6:        /* Invalid command given w/no args */
  948.             case -2:        /* Invalid command given w/args */
  949. #ifdef COMMENT
  950. #ifndef NOSPL
  951.             /* This is going to be really ugly... */
  952.             yy = mlook(mactab,atmbuf,nmac); /* Look in macro table */
  953.             if (yy > -1) {                /* If it's there */
  954.             if (zz == -2) {                /* insert "do" */
  955.                 char *mp;
  956.                 mp = malloc((int)strlen(cmdbuf) + 5);
  957.                 if (!mp) {
  958.                 printf("?malloc error 1\n");
  959.                 return(-2);
  960.                 }
  961.                 sprintf(mp,"do %s ",cmdbuf);
  962.                 strcpy(cmdbuf,mp);
  963.                 free(mp);
  964.             } else sprintf(cmdbuf,"do %s %c",atmbuf, CR);
  965.             if (ifcmd[cmdlvl] == 2)    /* This one doesn't count! */
  966.               ifcmd[cmdlvl]--;
  967.             debug(F111,"stuff cmdbuf",cmdbuf,zz);
  968.             repars = 1;    /* go for reparse */
  969.             continue;
  970.             } else {
  971.             char *p;
  972.             int n;
  973.             p = cmdbuf;
  974.             lp = line;     
  975.             n = LINBUFSIZ;
  976.             if (cmflgs == 0) printf("\n");
  977.             if (xxstring(p,&lp,&n) > -1) 
  978.               printf("?Invalid: %s\n",line);
  979.             else
  980.               printf("?Invalid: %s\n",cmdbuf);
  981.             } /* (fall thru...) */
  982. #else
  983.             printf("?Invalid: %s\n",cmdbuf);
  984. #endif /* NOSPL */
  985. #else
  986.             printf("?Invalid: %s\n",cmdbuf);
  987. #endif /* COMMENT */
  988.  
  989.         case -9:        /* Bad, error message already done */
  990.             success = 0;
  991.             debug(F110,"top-level cmkey failed",cmdbuf,0);
  992.             /* If in background w/ commands coming stdin, terminate */
  993.             if (pflag == 0 && tlevel < 0)
  994.               fatal("Kermit command error in background execution");
  995.             cmini(ckxech);    /* (fall thru) */
  996.  
  997.              case -3:        /* Empty command OK at top level */
  998.             repars = 0;        /* Don't need to reparse. */
  999.             continue;        /* Go back and get another command. */
  1000.  
  1001.         default:        /* Command was successful. */
  1002. #ifndef NOSPL
  1003.             debug(F101,"parser preparing to continue","",maclvl);
  1004. #endif /* NOSPL */
  1005.             repars = 0;        /* Don't need to reparse. */
  1006.             continue;        /* Go back and get another command. */
  1007.         }
  1008.     }
  1009. #ifndef NOSPL
  1010.     debug(F101,"parser breaks out of while loop","",maclvl);
  1011.     if (m && (cmdlvl < inlevel))  return((int) sstate);
  1012. #endif /* NOSPL */
  1013.     }
  1014.  
  1015. /* Got an action command, return start state. */
  1016.  
  1017. #ifdef COMMENT
  1018.     /* This is done in ckcpro.w instead, no need to do it twice. */
  1019.     /* Interrupts off only if remote */
  1020.     if (!local) connoi();
  1021. #endif /* COMMENT */
  1022.     return((int) sstate);
  1023. }
  1024.  
  1025. #ifndef NOSPL
  1026. /*
  1027.   OUTPUT command.
  1028.   Buffering and pacing added by L.I. Kirby, 5A(189), June 1993.
  1029. */
  1030. int
  1031. #ifdef CK_ANSIC
  1032. xxout(char *obuf, int obsize)
  1033. #else
  1034. xxout(obuf, obsize) char *obuf; int obsize; 
  1035. #endif /* CK_ANSIC */
  1036. /* xxout */ {                /* OUTPUT command's output function */
  1037.     int i;
  1038.  
  1039.     debug(F101,"xxout n","",obsize);
  1040.     debug(F101,"xxout pacing","",pacing);
  1041.  
  1042.     if (obsize <= 0) return(0);
  1043.     if (!obuf) return(0);
  1044.  
  1045.     debug(F110,"xxout string",obuf,strlen(obuf));
  1046.  
  1047.     if (pacing == 0) {              /* Is pacing enabled? */
  1048.     if ((local ?               /* No, write entire string at once */
  1049.          ttol((CHAR *)obuf, obsize) : /* to communications device */
  1050.          conxo(obsize, obuf))      /* or to console */
  1051.         != obsize)
  1052.       return(-1);
  1053.     } else {
  1054.     for (i = 0; i < obsize; i++) {    /* Write individual chars */
  1055.         if ((local ? ttoc(obuf[i]) : conoc(obuf[i])) < 0)
  1056.           return(-1);
  1057.         msleep(pacing);
  1058.     }
  1059.     }
  1060.     return(0);
  1061. }
  1062.  
  1063. /* Returns 0 on failure, 1 on success */
  1064.  
  1065. int
  1066. dooutput(s) char *s; {
  1067. /*
  1068.   Macros for OUTPUT command execution, "local" to this function,
  1069.   i.e. their definitions are in effect only for this function.
  1070. */
  1071. #define OBSIZE 80            /* Size of local character buffer */
  1072. #define obini() (obn=0,obp=obuf,0)
  1073. #define obfls() ((xxout(obuf,obn)<0)?-1:obini())
  1074. #define oboc(c) ((*obp++=(char)(c)),(((++obn)>=OBSIZE)?obfls():0))
  1075.  
  1076.     int x, xx, y, quote;        /* Workers */
  1077.     int obn;                /* Buffer offset (high water mark) */
  1078.     char obuf[OBSIZE];            /* Output character buffer, on stack */
  1079.     char *obp;                /* Pointer to output buffer */
  1080.  
  1081.     if (local) {            /* Condition external line */
  1082.     y = ttvt(speed,flow);
  1083.     if (y < 0) return(0);
  1084.     }
  1085.     quote = 0;                /* Initialize backslash (\) quote */
  1086.     obini();                /* Initialize output buffer */
  1087.  
  1088.     while (x = *s++) {            /* Loop through the string */
  1089.     y = 0;                /* Error code, 0 = no error. */
  1090.     if (x == CMDQ) {        /* Look for \b or \B in string */
  1091.             quote++;            /* Got \ */
  1092.         continue;            /* Get next character */
  1093.     } else if (quote) {        /* This character is quoted */
  1094.         if (quote == 1 && (x == 'b' || x == 'B')) {    /* If \b or \B */
  1095.         if (obfls() < 0)    /* Flush buffer first */
  1096.           goto outerr;
  1097.         debug(F100,"OUTPUT BREAK","",0);
  1098.         ttsndb();        /* send BREAK signal */
  1099.         quote = 0;        /* Turn off quote flag */
  1100.         continue;        /* and not the b or B */
  1101. #ifdef CK_LBRK
  1102.         } else if (quote == 1 && (x == 'l' || x == 'L')) { /* \l or \L */
  1103.         if (obfls() < 0)    /* Flush buffer first */
  1104.           goto outerr;
  1105.         debug(F100,"OUTPUT Long BREAK","",0);
  1106.         ttsndlb();        /* send Long BREAK signal */
  1107.         quote = 0;        /* Turn off quote flag */
  1108.         continue;        /* and not the l or L */
  1109. #endif /* CK_LBRK */
  1110.         } else {            /* if \ not followed by b or B */
  1111.         /* Note: Atari ST compiler won't allow macro call in "if ()" */
  1112.         xx = oboc(dopar(CMDQ));    /* Output the backslash. */
  1113.         if (xx < 0)
  1114.           goto outerr;
  1115.         quote = 0;        /* Turn off quote flag */
  1116.         }
  1117.     } else                /* No quote */
  1118.       quote = 0;            /* Turn off quote flag */
  1119.  
  1120.     xx = oboc(dopar((char)x));    /* Output this character */
  1121.     if (xx < 0)
  1122.       goto outerr;
  1123.     if (seslog && duplex)        /* Log the character if log is on */
  1124.       if (zchout(ZSFILE,(char)x) < 0) /* and connection is half duplex */
  1125.         seslog = 0;
  1126.     if (x == '\015') {        /* User typed carriage return */
  1127.         if (tnlm            /* If TERMINAL NEWLINE-MODE is ON */
  1128. #ifdef TNCODE
  1129.         || (network &&        /* Or we have a network connection */
  1130.             ttnproto == NP_TELNET && /* using TELNET protocol */
  1131.             tn_nlm        /* and TELNET NEWLINE-MODE is ON */
  1132.             )
  1133. #endif /* TNCODE */
  1134.         ) {
  1135.         xx = oboc(dopar('\012'));
  1136.         if (xx < 0)        /* Send LF too (CR => CRLF) */
  1137.           goto outerr;
  1138.         if (seslog && duplex)         /* Log the LF if appropriate */
  1139.           if (zchout(ZSFILE,'\012') < 0)
  1140.             seslog = 0;
  1141.         }
  1142.         if (obfls() < 0)        /* Flushing is required here! */
  1143.           goto outerr;
  1144.     }
  1145.     }
  1146.     if (obn > 0)            /* OUTPUT done */
  1147.       if (obfls() < 0)            /* Flush the buffer if necessary. */
  1148.     goto outerr;
  1149.     return(1);
  1150.  
  1151. outerr:                    /* OUTPUT command error handler */
  1152.     if (msgflg) printf("OUTPUT error\n");
  1153.     return(0);
  1154.  
  1155. /* Remove "local" OUTPUT macro defininitions */
  1156.  
  1157. #undef OBSIZE
  1158. #undef obini
  1159. #undef oboc
  1160. #undef obfls
  1161. }
  1162. #endif /* NOSPL */
  1163.  
  1164. /* Display version herald and initial prompt */
  1165.  
  1166. VOID
  1167. herald() {
  1168.     int x = 0;
  1169.     if (bgset > 0 || (bgset != 0 && backgrd != 0)) x = 1;
  1170.     debug(F101,"herald","",backgrd);
  1171.     if (x == 0)
  1172. #ifdef datageneral
  1173.       printf("%s,%s\nType ? or HELP for help\n",versio,ckxsys);
  1174. #else
  1175.       printf("%s,%s\n\rType ? or HELP for help\n",versio,ckxsys);
  1176. #endif /* datageneral */
  1177. }
  1178.  
  1179. #ifndef NOSPL
  1180. /*  M L O O K  --  Lookup the macro name in the macro table  */
  1181.  
  1182. /*
  1183.  Call this way:  v = mlook(table,word,n);
  1184.  
  1185.    table - a 'struct mtab' table.
  1186.    word  - the target string to look up in the table.
  1187.    n     - the number of elements in the table.
  1188.  
  1189.  The keyword table must be arranged in ascending alphabetical order, and
  1190.  all letters must be lowercase.
  1191.  
  1192.  Returns the table index, 0 or greater, if the name was found, or:
  1193.  
  1194.   -3 if nothing to look up (target was null),
  1195.   -2 if ambiguous,
  1196.   -1 if not found.
  1197.  
  1198.  A match is successful if the target matches a keyword exactly, or if
  1199.  the target is a prefix of exactly one keyword.  It is ambiguous if the
  1200.  target matches two or more keywords from the table.
  1201. */
  1202. int
  1203. mlook(table,cmd,n) struct mtab table[]; char *cmd; int n; {
  1204.  
  1205.     int i, v, cmdlen;
  1206.  
  1207. /* Lowercase & get length of target, if it's null return code -3. */
  1208.  
  1209.     if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
  1210.  
  1211. /* Not null, look it up */
  1212.  
  1213.     for (i = 0; i < n-1; i++) {
  1214.         if (!strcmp(table[i].kwd,cmd) ||
  1215.            ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
  1216.              strncmp(table[i+1].kwd,cmd,cmdlen))) {
  1217.                 return(i);
  1218.              }
  1219.         if (v) return(-2);
  1220.     }   
  1221.  
  1222. /* Last (or only) element */
  1223.  
  1224.     if (!strncmp(table[n-1].kwd,cmd,cmdlen)) {
  1225.         return(n-1);
  1226.     } else return(-1);
  1227. }
  1228.  
  1229. /* mxlook is like mlook, but an exact full-length match is required */
  1230.  
  1231. int
  1232. mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
  1233.     int i, cmdlen;
  1234.     if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
  1235.     for (i = 0; i < n; i++)
  1236.       if (((int)strlen(table[i].kwd) == cmdlen) &&
  1237.       (!strncmp(table[i].kwd,cmd,cmdlen))) return(i);
  1238.     return(-1);
  1239. }
  1240.  
  1241. /*
  1242.   This routine is for the benefit of those compilers that can't handle
  1243.   long string constants or continued lines within them.  Long predefined
  1244.   macros like FOR, WHILE, and XIF have their contents broken up into
  1245.   arrays of string pointers.  This routine concatenates them back into a
  1246.   single string again, and then calls the real addmac() routine to enter
  1247.   the definition into the macro table.
  1248. */
  1249. int
  1250. addmmac(nam,s) char *nam, *s[]; {    /* Add a multiline macro definition */
  1251.     int i, x, y; char *p;
  1252.     x = 0;                /* Length counter */
  1253.     for (i = 0; (y = (int)strlen(s[i])) > 0; i++) { /* Add up total length */
  1254.         debug(F111,"addmmac line",s[i],y);    
  1255.     x += y;
  1256.     }
  1257.     debug(F101,"addmmac lines","",i);
  1258.     debug(F101,"addmmac loop exit","",y);
  1259.     debug(F111,"addmmac length",nam,x);
  1260.     if (x < 0) return(-1);
  1261.  
  1262.     p = malloc(x+1);            /* Allocate space for all of it. */
  1263.     if (!p) {
  1264.     printf("?addmmac malloc error: %s\n",nam);
  1265.     debug(F110,"addmmac malloc error",nam,0);
  1266.     return(-1);
  1267.     }
  1268.     *p = '\0';                /* Start off with null string. */
  1269.     for (i = 0; *s[i]; i++)        /* Concatenate them all together. */
  1270.       strcat(p,s[i]);
  1271.     y = (int)strlen(p);            /* Final precaution. */
  1272.     debug(F111,"addmmac constructed string",p,y);
  1273.     if (y == x) {
  1274.     y = addmac(nam,p);        /* Add result to the macro table. */
  1275.     } else {
  1276.     debug(F100,"addmmac length mismatch","",0);
  1277.     printf("\n!addmmac internal error!\n");
  1278.     y = -1;
  1279.     }
  1280.     free(p);                /* Free the temporary copy. */
  1281.     return(y);    
  1282. }
  1283.  
  1284. /* Here is the real addmac routine. */
  1285.  
  1286. int
  1287. addmac(nam,def) char *nam, *def; {    /* Add a macro to the macro table */
  1288.     int i, x, y, z, namlen, deflen;
  1289.     char *p, c;
  1290.  
  1291.     if (!nam) return(-1);
  1292.     namlen = (int)strlen(nam);        /* Get argument lengths */
  1293.     debug(F111,"addmac nam",nam,namlen);
  1294.     if (!def) {                /* Watch out for null pointer */
  1295.     deflen = 0;
  1296.     debug(F111,"addmac def","(null pointer)",deflen);
  1297.     } else {
  1298.     deflen = (int)strlen(def);
  1299.     debug(F111,"addmac def",def,deflen);
  1300.     }
  1301.     if (deflen < 0) return(-1);        /* strlen() failure, fail. */
  1302.     if (namlen < 1) return(-1);        /* No name given, fail. */
  1303.  
  1304.     if (*nam == CMDQ) nam++;        /* Backslash quote? */
  1305.     if (*nam == '%') {            /* Yes, if it's a variable name, */
  1306.     delmac(nam);            /* Delete any old value. */
  1307.     if (!(c = *(nam + 1))) return(-1); /* Variable name letter or digit */
  1308.     if (deflen < 1) {        /* Null definition */
  1309.         p = NULL;            /* Better not malloc or strcpy! */
  1310.     } else {            /* A substantial definition */
  1311.         p = malloc(deflen + 1);    /* Allocate space for it */
  1312.         if (!p) {
  1313.         printf("?addmac malloc error 2\n");
  1314.         return(-1);
  1315.         } else strcpy(p,def);    /* Copy definition into new space */
  1316.     }
  1317.  
  1318.     /* Now p points to the definition, or is a null pointer */
  1319.  
  1320.     if (p)
  1321.       debug(F110,"addmac p",p,0);
  1322.     else
  1323.       debug(F110,"addmac p","(null pointer)",0);
  1324.  
  1325.     if (c >= '0' && c <= '9') {    /* Digit variable */
  1326.         if (maclvl < 0) {        /* Are we calling or in a macro? */
  1327.         g_var[c] = p;        /* No, it's a global "top level" one */
  1328.         debug(F101,"addmac numeric global maclvl","",maclvl);
  1329.         } else {            /* Yes, it's a macro argument */
  1330.         m_arg[maclvl][c - '0'] = p;
  1331.         debug(F101,"addmac macro arg maclvl","",maclvl);
  1332.         }
  1333.     } else {            /* It's a global variable */
  1334.         if (c < 33 || c > GVARS) return(-1);
  1335.         if (isupper(c)) c = tolower(c);
  1336.         g_var[c] = p;        /* Put pointer in global-var table */
  1337.         debug(F100,"addmac global","",0);
  1338.     }
  1339.     return(0);
  1340.     } else if (*nam == '&') {        /* An array reference? */
  1341.     char **q;
  1342.     if ((y = arraynam(nam,&x,&z)) < 0) /* If syntax is bad */
  1343.       return(-1);            /* return -1. */
  1344.     if (chkarray(x,z) < 0)        /* If array not declared or */
  1345.       return(-2);            /* subscript out of range, ret -2 */
  1346.     delmac(nam);            /* Delete any current definition. */
  1347.     x -= 96;            /* Convert name letter to index. */
  1348.     if ((q = a_ptr[x]) == NULL)    /* If array not declared, */
  1349.       return(-3);            /* return -3. */
  1350.     if (deflen > 0) {
  1351.         if ((p = malloc(deflen+1)) == NULL) { /* Allocate space */
  1352.         printf("addmac macro error 7: %s\n",nam);
  1353.         return(-4);        /* for new def, return -4 on fail. */
  1354.         }
  1355.         strcpy(p,def);        /* Copy definition into new space. */
  1356.     } else p = NULL;
  1357.     q[z] = p;            /* Store pointer to it. */
  1358.     return(0);            /* Done. */
  1359.     } else debug(F110,"addmac macro def",nam,0);
  1360.  
  1361. /* Not a macro argument or a variable, so it's a macro definition */
  1362.  
  1363.     lower(nam);                /* Lowercase the name */
  1364.     if (mxlook(mactab,nam,nmac) > -1)    /* Look up, requiring exact match */
  1365.       delmac(nam);            /* if it's there, delete it. */
  1366.     debug(F111,"addmac table size",nam,nmac);
  1367.     for (y = 0;                /* Find the alphabetical slot */
  1368.      y < MAC_MAX && mactab[y].kwd != NULL && strcmp(nam,mactab[y].kwd) > 0;
  1369.      y++) ;
  1370.     if (y == MAC_MAX) {            /* No more room. */
  1371.     debug(F101,"addmac table overflow","",y);
  1372.     return(-1);
  1373.     } else debug(F111,"addmac position",nam,y);
  1374.     if (mactab[y].kwd != NULL) {    /* Must insert */
  1375.     for (i = nmac; i > y; i--) {    /* Move the rest down one slot */
  1376.         mactab[i].kwd = mactab[i-1].kwd;
  1377.         mactab[i].mval = mactab[i-1].mval;
  1378.         mactab[i].flgs = mactab[i-1].flgs;
  1379.     }
  1380.     }
  1381.     p = malloc(namlen + 1);        /* Allocate space for name */
  1382.     if (!p) {
  1383.     printf("?addmac malloc error 3: %s\n",nam);
  1384.     return(-1);
  1385.     }
  1386.     strcpy(p,nam);            /* Copy name into new space */
  1387.     mactab[y].kwd = p;            /* Add pointer to table */
  1388.  
  1389.     if (deflen > 0) {            /* Same deal for definition */
  1390.     p = malloc(deflen + 1);        /* but watch out for null pointer */
  1391.     if (p == NULL) {
  1392.         printf("?addmac malloc error 5: %s\n", nam);
  1393.         free(mactab[y].kwd);
  1394.         mactab[y].kwd = NULL;
  1395.         return(-1);
  1396.     } else strcpy(p,def);        /* Copy the definition */
  1397.     } else p = NULL;
  1398.     mactab[y].mval = p;
  1399.     mactab[y].flgs = 0;
  1400.     nmac++;                /* Count this macro */
  1401.     return(y);
  1402. }
  1403.  
  1404. int
  1405. delmac(nam) char *nam; {        /* Delete the named macro */
  1406.     int i, x, z;
  1407.     char *p, c;
  1408.  
  1409.     if (!nam) return(0);        /* Watch out for null pointer */
  1410.     debug(F110,"delmac nam",nam,0);
  1411.     if (*nam == CMDQ) nam++;
  1412.     if (*nam == '%') {            /* If it's a variable name */
  1413.     if (!(c = *(nam+1))) return(0);    /* Get variable name letter or digit */
  1414.     p = (char *)0;            /* Initialize value pointer */
  1415.     if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */
  1416.         p = m_arg[maclvl][c - '0'];    /* Get pointer from macro-arg table */
  1417.         m_arg[maclvl][c - '0'] = NULL; /* Zero the table pointer */
  1418.     } else {            /* It's a global variable */
  1419.         if (c < 33 || c > GVARS) return(0);
  1420.         p = g_var[c];        /* Get pointer from global-var table */
  1421.         g_var[c] = NULL;        /* Zero the table entry */
  1422.     }
  1423.     if (p) {
  1424.         debug(F110,"delmac def",p,0);
  1425.         free(p);            /* Free the storage */
  1426.     } else debug(F110,"delmac def","(null pointer)",0);
  1427.     return(0);
  1428.     }
  1429.         
  1430.     if (*nam == '&') {            /* An array reference? */
  1431.     char **q;
  1432.     if (arraynam(nam,&x,&z) < 0)    /* If syntax is bad */
  1433.       return(-1);            /* return -1. */
  1434.     x -= 96;            /* Convert name to number. */
  1435.     if ((q = a_ptr[x]) == NULL)    /* If array not declared, */
  1436.       return(-2);            /* return -2. */
  1437.     if (z > a_dim[x])        /* If subscript out of range, */
  1438.       return(-3);            /* return -3. */
  1439.     if (q[z]) {            /* If there is an old value, */
  1440.         debug(F110,"delman def",q[z],0);
  1441.         free(q[z]);            /* delete it. */
  1442.         q[z] = NULL;
  1443.     } else debug(F110,"delmac def","(null pointer)",0);
  1444.     }
  1445.  
  1446.    /* Not a variable or an array, so it must be a macro. */
  1447.  
  1448.     if ((x = mlook(mactab,nam,nmac)) < 0) { /* Look it up */
  1449.     debug(F111,"delmac mlook",nam,x);
  1450.     return(x);
  1451.     }
  1452.     if (mactab[x].kwd)            /* Free the storage for the name */
  1453.       free(mactab[x].kwd);
  1454.     if (mactab[x].mval)            /* and for the definition */
  1455.       free(mactab[x].mval);
  1456.  
  1457.     for (i = x; i < nmac; i++) {    /* Now move up the others. */
  1458.     mactab[i].kwd = mactab[i+1].kwd;
  1459.     mactab[i].mval = mactab[i+1].mval;
  1460.     mactab[i].flgs = mactab[i+1].flgs;
  1461.     }
  1462.     nmac--;                /* One less macro */
  1463.     mactab[nmac].kwd = NULL;        /* Delete last item from table */
  1464.     mactab[nmac].mval = NULL;
  1465.     mactab[nmac].flgs = 0;
  1466.     return(0);
  1467. }
  1468.  
  1469. VOID
  1470. initmac() {                /* Init macro & variable tables */
  1471.     int i, j;
  1472.  
  1473.     nmac = 0;                /* No macros */
  1474.     for (i = 0; i < MAC_MAX; i++) {    /* Initialize the macro table */
  1475.     mactab[i].kwd = NULL;
  1476.     mactab[i].mval = NULL;
  1477.     mactab[i].flgs = 0;
  1478.     }
  1479.     for (i = 0; i < MACLEVEL; i++) {    /* Init the macro argument tables */
  1480.     mrval[i] = NULL;
  1481.     for (j = 0; j < 10; j++) {
  1482.         m_arg[i][j] = NULL;
  1483.     }
  1484.     }
  1485.     for (i = 0; i < GVARS; i++) {    /* And the global variables table */
  1486.     g_var[i] = NULL;
  1487.     }
  1488.     for (i = 0; i < 26; i++) {        /* And the table of arrays */
  1489.     a_ptr[i] = (char **) NULL;    /* Null pointer for each */
  1490.     a_dim[i] = 0;            /* and a dimension of zero */
  1491.     }
  1492. }
  1493.  
  1494. int
  1495. popclvl() {                /* Pop command level, return cmdlvl */
  1496.     if (cmdlvl < 1) {            /* If we're already at top level */
  1497.     cmdlvl = 0;            /* just make sure all the */
  1498.     tlevel = -1;            /* stack pointers are set right */
  1499.     maclvl = -1;            /* and return */
  1500.     } else if (cmdstk[cmdlvl].src == CMD_TF) { /* Reading from TAKE file? */
  1501.     if (tlevel > -1) {        /* Yes, */
  1502.         if (tfnam[tlevel]) {
  1503.         free(tfnam[tlevel]);
  1504.         tfnam[tlevel] = NULL;
  1505.         }
  1506.         fclose(tfile[tlevel--]);    /* close it and pop take level */
  1507.         cmdlvl--;            /* pop command level */
  1508.     } else tlevel = -1;
  1509.     } else if (cmdstk[cmdlvl].src == CMD_MD) { /* In a macro? */
  1510.     if (maclvl > -1) {        /* Yes, */
  1511.         debug(F111,"popclvl before",macx[maclvl],maclvl);
  1512.         macp[maclvl] = "";        /* set macro pointer to null string */
  1513.         *cmdbuf = '\0';        /* clear the command buffer */
  1514.         if (mrval[maclvl+1]) {    /* Free any deeper return values. */
  1515.         free(mrval[maclvl+1]);
  1516.         mrval[maclvl+1] = NULL;
  1517.         }
  1518.         maclvl--;            /* pop macro level */
  1519.         cmdlvl--;            /* and command level */
  1520.         debug(F111,"popclvl after ",
  1521.           macx[maclvl] ? macx[maclvl] : "",maclvl);
  1522.     } else maclvl = -1;
  1523.     }
  1524. #ifndef MAC
  1525.     if (cmdlvl < 1) {            /* If back at top level */
  1526.     conint(trap,stptrap);        /* Fix interrupts */
  1527.     bgchk();            /* Check background status */
  1528.     concb((char)escape);        /* Go into cbreak mode */
  1529.     }
  1530. #endif /* MAC */
  1531.     return(cmdlvl < 1 ? 0 : cmdlvl);    /* Return command level */
  1532. }
  1533. #else /* No script programming language */
  1534. int popclvl() {                /* Just close current take file. */
  1535.     if (tlevel > -1) {            /* if any... */
  1536.     if (tfnam[tlevel]) {
  1537.         free(tfnam[tlevel]);
  1538.         tfnam[tlevel] = NULL;
  1539.     }
  1540.     fclose(tfile[tlevel--]);
  1541.     }
  1542.     if (tlevel == -1) {            /* And if back at top level */
  1543.     conint(trap,stptrap);        /* check and set interrupts */
  1544.         bgchk();            /* and background status */
  1545.         concb((char)escape);        /* and go back into cbreak mode. */
  1546.     }
  1547.     return(tlevel + 1);
  1548. }
  1549. #endif /* NOSPL */
  1550.  
  1551. /* STOP - get back to C-Kermit prompt, no matter where from. */
  1552.  
  1553. int
  1554. dostop() {
  1555.     while ( popclvl() )  ;    /* Pop all macros & take files */
  1556. #ifndef NOSPL
  1557.     while (cmpop() > -1) ;    /* And all recursive cmd pkg invocations */
  1558. #endif /* NOSPL */
  1559.     cmini(ckxech);        /* Clear the command buffer. */
  1560.     return(0);
  1561. }
  1562.  
  1563.  
  1564. /* Close the given log */
  1565.  
  1566. int
  1567. doclslog(x) int x; {
  1568.     int y;
  1569.     switch (x) {
  1570. #ifdef DEBUG
  1571.     case LOGD:
  1572.         if (deblog == 0) {
  1573.         printf("?Debugging log wasn't open\n");
  1574.         return(0);
  1575.         }
  1576.         *debfil = '\0';
  1577.         deblog = 0;
  1578.         return(zclose(ZDFILE));
  1579. #endif /* DEBUG */
  1580.  
  1581.     case LOGP:
  1582.         if (pktlog == 0) {
  1583.         printf("?Packet log wasn't open\n");
  1584.         return(0);
  1585.         }
  1586.         *pktfil = '\0';
  1587.         pktlog = 0;
  1588.         return(zclose(ZPFILE));
  1589.  
  1590.     case LOGS:
  1591.         if (seslog == 0) {
  1592.         printf("?Session log wasn't open\n");
  1593.         return(0);
  1594.         }
  1595.         *sesfil = '\0';
  1596.         seslog = 0;
  1597.         return(zclose(ZSFILE));
  1598.  
  1599. #ifdef TLOG
  1600.         case LOGT:
  1601.         if (tralog == 0) {
  1602.         printf("?Transaction log wasn't open\n");
  1603.         return(0);
  1604.         }
  1605.         *trafil = '\0';
  1606.         tralog = 0;
  1607.         return(zclose(ZTFILE));
  1608. #endif /* TLOG */
  1609.  
  1610. #ifndef NOSPL
  1611.           case LOGW:            /* WRITE file */
  1612.       case LOGR:            /* READ file */
  1613.         y = (x == LOGR) ? ZRFILE : ZWFILE;
  1614.         if (chkfn(y) < 1)        /* If no file to close */
  1615.           return(1);        /* succeed silently. */
  1616.         return(zclose(y));        /* Otherwise, close the file. */
  1617. #endif /* NOSPL */
  1618.  
  1619.     default:
  1620.         printf("\n?Unexpected log designator - %d\n", x);
  1621.         return(0);
  1622.     }
  1623. }
  1624.  
  1625. #ifndef NOSERVER
  1626. #ifndef NOFRILLS
  1627. static char *nm[] = { "disabled", "enabled" };
  1628. #endif /* NOFRILLS */
  1629. #endif /* NOSERVER */
  1630.  
  1631. static int slc = 0;            /* Screen line count */
  1632.  
  1633. #ifndef NOSHOW
  1634. #ifndef NOFRILLS
  1635. #define xxdiff(v,sys) strncmp(v,sys,strlen(sys))
  1636. VOID
  1637. shover() {
  1638.     printf("\nVersions:\n %s\n Numeric: %ld",versio,vernum);
  1639.     if (verwho) printf("-%d",verwho);
  1640.     printf(xxdiff(ckxv,ckxsys) ? "\n %s for%s\n" : "\n %s\n",ckxv,ckxsys);
  1641.     printf(xxdiff(ckzv,ckzsys) ? " %s for%s\n" : " %s\n",ckzv,ckzsys);
  1642.     printf(" %s\n",protv);
  1643.     printf(" %s\n",fnsv);
  1644.     printf(" %s\n %s\n",cmdv,userv);
  1645. #ifndef NOCSETS
  1646.     printf(" %s\n",xlav);
  1647. #endif /* NOCSETS */
  1648. #ifndef MAC
  1649.     printf(" %s\n",connv);
  1650. #endif /* MAC */
  1651. #ifndef NODIAL
  1652.     printf(" %s\n",dialv);
  1653. #endif /* NODIAL */
  1654. #ifndef NOSCRIPT
  1655.     printf(" %s\n",loginv);
  1656. #endif /* NOSCRIPT */
  1657. #ifdef NETCONN
  1658.     printf(" %s\n",cknetv);
  1659. #ifdef OS2
  1660.     printf(" %s\n",ckonetv);
  1661. #endif /* OS2 */
  1662. #endif /* NETCONN */
  1663.     printf("\n");
  1664. }
  1665.  
  1666. VOID
  1667. shofea() {
  1668.     int flag = 0;
  1669. #ifdef OS2
  1670. #ifdef M_I286
  1671.     printf("\nOS/2 16-bit.\n");
  1672. #else
  1673.     printf("\nOS/2 32-bit.\n");
  1674. #endif /* M_I286 */
  1675. #endif /* OS2 */
  1676.     printf("\nSpecial features:\n");
  1677. #ifdef NETCONN
  1678.     printf(" Network support (type SHOW NET for further info)\n");
  1679. #endif /* NETCONN */
  1680. #ifdef CK_RTSCTS
  1681.     printf(" Hardware flow control\n");
  1682. #endif /* CK_RTSCTS */
  1683. #ifndef NOCSETS
  1684.     printf(" Latin-1 (West European) character-set translation\n");
  1685. #ifdef LATIN2
  1686.     printf(" Latin-2 (East European) character-set translation\n");
  1687. #endif /* LATIN2 */
  1688. #ifdef CYRILLIC
  1689.     printf(" Cyrillic (Russian, Ukrainian, etc) character-set translation\n");
  1690. #endif /* CYRILLIC */
  1691. #ifdef HEBREW
  1692.     printf(" Hebrew character-set translation\n");
  1693. #endif /* HEBREW */
  1694. #ifdef KANJI
  1695.     printf(" Kanji (Japanese) character-set translation\n");
  1696. #endif /* KANJI */
  1697. #endif /* NOCSETS */
  1698.  
  1699. #ifdef CK_CURSES
  1700.     printf(" Fullscreen file transfer display\n");
  1701. #endif /* CK_CURSES */
  1702.  
  1703. #ifdef CK_SPEED
  1704.     printf(" Control-character unprefixing\n");
  1705. #endif /* CK_SPEED */
  1706.  
  1707.     printf("\nFeatures not included:\n");
  1708. #ifndef CK_CURSES
  1709. #ifndef MAC
  1710.     printf(" No fullscreen file transfer display\n");
  1711.     flag = 1;
  1712. #endif /* MAC */
  1713. #endif /* CK_CURSES */
  1714. #ifdef NOSERVER
  1715.     printf(" No server mode\n");
  1716.     flag = 1;
  1717. #endif /* NOSERVER */
  1718. #ifdef NODEBUG
  1719.     printf(" No debugging\n");
  1720.     flag = 1;
  1721. #endif /* NODEBUG */
  1722. #ifdef NOTLOG
  1723.     printf(" No transaction log\n");
  1724.     flag = 1;
  1725. #endif /* NOTLOG */
  1726. #ifdef NOHELP
  1727.     printf(" No built-in help\n");
  1728.     flag = 1;
  1729. #endif /* NOHELP */
  1730. #ifndef NETCONN
  1731.     printf(" No network support\n");
  1732.     flag = 1;
  1733. #endif /* NETCONN */
  1734. #ifdef NOMSEND
  1735.     printf(" No MSEND command\n");
  1736.     flag = 1;
  1737. #endif /* NOMSEND */
  1738. #ifdef NODIAL
  1739.     printf(" No DIAL command\n");
  1740.     flag = 1;
  1741. #else
  1742. #ifdef MINIDIAL
  1743.     printf(" DIAL command for modems other than Hayes, CCITT, and Unknown\n");
  1744.     flag = 1;
  1745. #endif /* MINIDIAL */
  1746. #ifndef CK_RTSCTS
  1747.     printf(" No hardware flow control\n");
  1748.     flag = 1;
  1749. #endif /* CK_RTSCTS */
  1750. #endif /* NODIAL */
  1751. #ifdef NOXMIT
  1752.     printf(" No TRANSMIT command\n");
  1753.     flag = 1;
  1754. #endif /* NOXMIT */
  1755. #ifdef NOSCRIPT
  1756.     printf(" No SCRIPT command\n");
  1757.     flag = 1;
  1758. #endif /* NOSCRIPT */
  1759. #ifdef NOSPL
  1760.     printf(" No script programming features\n");
  1761.     flag = 1;
  1762. #endif /* NOSPL */
  1763. #ifdef NOCSETS
  1764.     printf(" No character-set translation\n");
  1765.     flag = 1;
  1766. #else
  1767. #ifndef LATIN2
  1768.     printf(" No Latin-2 character-set translation\n");
  1769.     flag = 1;
  1770. #endif /* LATIN2 */
  1771. #ifdef NOHEBREW
  1772.     printf(" No Hebrew character-set translation\n");
  1773.     flag = 1;
  1774. #endif /* NOHEBREW */
  1775. #ifdef NOCYRIL
  1776.     printf(" No Cyrillic character-set translation\n");
  1777.     flag = 1;
  1778. #endif /* NOCYRIL */
  1779. #ifndef KANJI
  1780.     printf(" No Kanji character-set translation\n");
  1781.     flag = 1;
  1782. #endif /* KANJI */
  1783. #endif /* NOCSETS */
  1784. #ifdef NOCMDL
  1785.     printf(" No command-line arguments\n");
  1786.     flag = 1;
  1787. #endif /* NOCMDL */
  1788. #ifdef NOFRILLS
  1789.     printf(" No frills\n");
  1790.     flag = 1;
  1791. #endif /* NOFRILLS */
  1792. #ifdef NOPUSH
  1793.     printf(" No escape to system\n");
  1794.     flag = 1;
  1795. #endif /* NOPUSH */
  1796. #ifdef NOJC
  1797. #ifdef UNIX
  1798.     printf(" No UNIX job control\n");
  1799.     flag = 1;
  1800. #endif /* UNIX */
  1801. #endif /* NOJC */
  1802. #ifdef NOSETKEY
  1803.     printf(" No SET KEY command\n");
  1804.     flag = 1;
  1805. #endif /* NOSETKEY */
  1806. #ifdef NOESCSEQ
  1807.     printf(" No ANSI escape sequence recognition\n");
  1808.     flag = 1;
  1809. #endif /* NOESCSEQ */
  1810. #ifndef PARSENSE
  1811.     printf(" No automatic parity detection\n");
  1812.     flag = 1;
  1813. #endif /* PARSENSE */
  1814. #ifndef CK_SPEED
  1815.     printf(" No control-character unprefixing\n");
  1816.     flag = 1;
  1817. #endif /* CK_SPEED */
  1818.     if (flag == 0) printf(" None\n");
  1819. /*
  1820.   Print compile-time (-D) options, as well as C preprocessor
  1821.   predefined symbols that might affect us...
  1822. */
  1823. #ifdef __DATE__                /* GNU and other ANSI */
  1824. #ifdef __TIME__
  1825.     printf("\nCompiled %s %s, options:\n", __DATE__, __TIME__);
  1826. #else
  1827.     printf("\nCompiled %s, options:\n", __DATE__);
  1828. #endif /* __TIME__ */
  1829. #else /* !__DATE__ */
  1830.     printf("\nCompiler options:\n");
  1831. #endif /* __DATE__ */
  1832.  
  1833. #ifdef DEBUG
  1834. #ifdef IFDEBUG
  1835.     prtopt(" IFDEBUG");
  1836. #else
  1837.     prtopt(" DEBUG");
  1838. #endif /* IFDEBUG */
  1839. #endif /* DEBUG */
  1840. #ifdef TLOG
  1841.     prtopt(" TLOG");
  1842. #endif /* TLOG */
  1843. #ifdef XFRCAN
  1844.     prtopt(" XFRCAN");
  1845. #endif /* XFRCAN */
  1846. #ifdef CK_SPEED
  1847.     prtopt(" CK_SPEED");
  1848. #endif /* CK_SPEED */
  1849. #ifdef NODIAL
  1850.     prtopt(" NODIAL");
  1851. #endif /* NODIAL */
  1852. #ifdef MINIDIAL
  1853.     prtopt(" MINIDIAL");
  1854. #endif /* MINIDIAL */
  1855. #ifdef DYNAMIC
  1856.     prtopt(" DYNAMIC");
  1857. #endif /* IFDEBUG */
  1858. #ifndef NOSPL
  1859.     sprintf(line," CMDDEP=%d",CMDDEP);
  1860.     prtopt(line);
  1861. #endif /* NOSPL */
  1862. #ifdef UNIX
  1863.     prtopt(" UNIX");
  1864. #endif /* UNIX */
  1865. #ifdef VMS
  1866.     prtopt(" VMS");
  1867. #endif /* VMS */
  1868. #ifdef vms
  1869.     prtopt(" vms");
  1870. #endif /* vms */
  1871. #ifdef VMSSHARE
  1872.     prtopt(" VMSSHARE");
  1873. #endif /* VMSSHARE */
  1874. #ifdef datageneral
  1875.     prtopt(" datageneral");
  1876. #endif /* datageneral */
  1877. #ifdef apollo
  1878.     prtopt(" apollo");
  1879. #endif /* apollo */
  1880. #ifdef aegis
  1881.     prtopt(" aegis");
  1882. #endif /* aegis */
  1883. #ifdef A986
  1884.     prtopt(" A986");
  1885. #endif /* A986 */
  1886. #ifdef AMIGA
  1887.     prtopt(" AMIGA");
  1888. #endif /* AMIGA */
  1889. #ifdef CONVEX9
  1890.     prtopt(" CONVEX9");
  1891. #endif /* CONVEX9 */
  1892. #ifdef CONVEX10
  1893.     prtopt(" CONVEX10");
  1894. #endif /* CONVEX9 */
  1895. #ifdef MAC
  1896.     prtopt(" MAC");
  1897. #endif /* MAC */
  1898. #ifdef AUX
  1899.     prtopt(" AUX");
  1900. #endif /* AUX */
  1901. #ifdef OS2
  1902.     prtopt(" OS2");
  1903. #endif /* OS2 */
  1904. #ifdef OS9
  1905.     prtopt(" OS9");
  1906. #endif /* OS9 */
  1907. #ifdef MSDOS
  1908.     prtopt(" MSDOS");
  1909. #endif /* MSDOS */
  1910. #ifdef DIRENT
  1911.     prtopt(" DIRENT");
  1912. #endif /* DIRENT */
  1913. #ifdef SDIRENT
  1914.     prtopt(" SDIRENT");
  1915. #endif /* SDIRENT */
  1916. #ifdef NDIR
  1917.     prtopt(" NDIR");
  1918. #endif /* NDIR */
  1919. #ifdef XNDIR
  1920.     prtopt(" XNDIR");
  1921. #endif /* XNDIR */
  1922. #ifdef MATCHDOT
  1923.     prtopt(" MATCHDOT");
  1924. #endif /* MATCHDOT */
  1925. #ifdef SAVEDUID
  1926.     prtopt(" SAVEDUID");
  1927. #endif /* SAVEDUID */
  1928. #ifdef RENAME
  1929.     prtopt(" RENAME");
  1930. #endif /* RENAME */
  1931. #ifdef NOCCTRAP
  1932.     prtopt(" NOCCTRAP");
  1933. #endif /* NOCCTRAP */
  1934. #ifdef TCPSOCKET
  1935.     prtopt(" TCPSOCKET");
  1936. #endif /* TCPSOCKET */
  1937. #ifdef SUNX25
  1938.     prtopt(" SUNX25");
  1939. #endif /* SUNX25 */
  1940. #ifdef DECNET
  1941.     prtopt(" DECNET");
  1942. #endif /* DECNET */
  1943. #ifdef ATT7300
  1944.     prtopt(" ATT7300");
  1945. #endif /* ATT7300 */
  1946. #ifdef ATT6300
  1947.     prtopt(" ATT6300");
  1948. #endif /* ATT6300 */
  1949. #ifdef HDBUUCP
  1950.     prtopt(" HDBUUCP");
  1951. #endif /* HDBUUCP */
  1952. #ifdef NOUUCP
  1953.     prtopt(" NOUUCP");
  1954. #endif /* NOUUCP */
  1955. #ifdef LONGFN
  1956.     prtopt(" LONGFN");
  1957. #endif /* LONGFN */
  1958. #ifdef RDCHK
  1959.     prtopt(" RDCHK");
  1960. #endif /* RDCHK */
  1961. #ifdef NAP
  1962.     prtopt(" NAP");
  1963. #endif /* NAP */
  1964. #ifdef NAPHACK
  1965.     prtopt(" NAPHACK");
  1966. #endif /* NAPHACK */
  1967. #ifdef CK_POLL
  1968.     prtopt(" CK_POLL");
  1969. #endif /* CK_POLL */
  1970. #ifdef NOIEXTEN
  1971.     prtopt(" NOIEXTEN");
  1972. #endif /* NOIEXTEN */
  1973. #ifdef EXCELAN
  1974.     prtopt(" EXCELAN");
  1975. #endif /* EXCELAN */
  1976. #ifdef PARAMH
  1977.     prtopt(" PARAMH");
  1978. #endif /* PARAMH */
  1979. #ifdef INTERLAN
  1980.     prtopt(" INTERLAN");
  1981. #endif /* INTERLAN */
  1982. #ifdef NOFILEH
  1983.     prtopt(" NOFILEH");
  1984. #endif /* NOFILEH */
  1985. #ifdef NOSYSIOCTLH
  1986.     prtopt(" NOSYSIOCTLH");
  1987. #endif /* NOSYSIOCTLH */
  1988. #ifdef DCLPOPEN
  1989.     prtopt(" DCLPOPEN");
  1990. #endif /* DCLPOPEN */
  1991. #ifdef NOSETBUF
  1992.     prtopt(" NOSETBUF");
  1993. #endif /* NOSETBUF */
  1994. #ifdef NOFDZERO
  1995.     prtopt(" NOFDZERO");
  1996. #endif /* NOFDZERO */
  1997. #ifdef NOPOPEN
  1998.     prtopt(" NOPOPEN");
  1999. #endif /* NOPOPEN */
  2000. #ifdef NOPARTIAL
  2001.     prtopt(" NOPARTIAL");
  2002. #endif /* NOPARTIAL */
  2003. #ifdef NOSETREU
  2004.     prtopt(" NOSETREU");
  2005. #endif /* NOSETREU */
  2006. #ifdef _POSIX_SOURCE
  2007.     prtopt(" _POSIX_SOURCE");
  2008. #endif /* _POSIX_SOURCE */
  2009. #ifdef LCKDIR
  2010.     prtopt(" LCKDIR");
  2011. #endif /* LCKDIR */
  2012. #ifdef ACUCNTRL
  2013.     prtopt(" ACUCNTRL");
  2014. #endif /* ACUCNTRL */
  2015. #ifdef BSD4
  2016.     prtopt(" BSD4");
  2017. #endif /* BSD4 */
  2018. #ifdef BSD44
  2019.     prtopt(" BSD44");
  2020. #endif /* BSD44 */
  2021. #ifdef BSD41
  2022.     prtopt(" BSD41");
  2023. #endif /* BSD41 */
  2024. #ifdef BSD43
  2025.     prtopt(" BSD43");
  2026. #endif /* BSD43 */
  2027. #ifdef BSD29
  2028.     prtopt(" BSD29");
  2029. #endif /* BSD29 */
  2030. #ifdef V7
  2031.     prtopt(" V7");
  2032. #endif /* V7 */
  2033. #ifdef AIX370
  2034.     prtopt(" AIX370");
  2035. #endif /* AIX370 */
  2036. #ifdef RTAIX
  2037.     prtopt(" RTAIX");
  2038. #endif /* RTAIX */
  2039. #ifdef HPUX
  2040.     prtopt(" HPUX");
  2041. #endif /* HPUX */
  2042. #ifdef HPUXPRE65
  2043.     prtopt(" HPUXPRE65");
  2044. #endif /* HPUXPRE65 */
  2045. #ifdef DGUX
  2046.     prtopt(" DGUX");
  2047. #endif /* DGUX */
  2048. #ifdef DGUX430
  2049.     prtopt(" DGUX430");
  2050. #endif /* DGUX430 */
  2051. #ifdef DGUX540
  2052.     prtopt(" DGUX540");
  2053. #endif /* DGUX540 */
  2054. #ifdef sony_news
  2055.     prtopt(" sony_news");
  2056. #endif /* sony_news */
  2057. #ifdef CIE
  2058.     prtopt(" CIE");
  2059. #endif /* CIE */
  2060. #ifdef XENIX
  2061.     prtopt(" XENIX");
  2062. #endif /* XENIX */
  2063. #ifdef SCO_XENIX
  2064.     prtopt(" SCO_XENIX");
  2065. #endif /* SCO_XENIX */
  2066. #ifdef ISIII
  2067.     prtopt(" ISIII");
  2068. #endif /* ISIII */
  2069. #ifdef I386IX
  2070.     prtopt(" I386IX");
  2071. #endif /* I386IX */
  2072. #ifdef RTU
  2073.     prtopt(" RTU");
  2074. #endif /* RTU */
  2075. #ifdef PROVX1
  2076.     prtopt(" PROVX1");
  2077. #endif /* PROVX1 */
  2078. #ifdef PYRAMID
  2079.     prtopt(" PYRAMID");
  2080. #endif /* PYRAMID */
  2081. #ifdef TOWER1
  2082.     prtopt(" TOWER1");
  2083. #endif /* TOWER1 */
  2084. #ifdef UTEK
  2085.     prtopt(" UTEK");
  2086. #endif /* UTEK */
  2087. #ifdef ZILOG
  2088.     prtopt(" ZILOG");
  2089. #endif /* ZILOG */
  2090. #ifdef TRS16
  2091.     prtopt(" TRS16");
  2092. #endif /* TRS16 */
  2093. #ifdef MINIX
  2094.     prtopt(" MINIX");
  2095. #endif /* MINIX */
  2096. #ifdef C70
  2097.     prtopt(" C70");
  2098. #endif /* C70 */
  2099. #ifdef AIXPS2
  2100.     prtopt(" AIXPS2");
  2101. #endif /* AIXPS2 */
  2102. #ifdef AIXRS
  2103.     prtopt(" AIXRS");
  2104. #endif /* AIXRS */
  2105. #ifdef UTSV
  2106.     prtopt(" UTSV");
  2107. #endif /* UTSV */
  2108. #ifdef ATTSV
  2109.     prtopt(" ATTSV");
  2110. #endif /* ATTSV */
  2111. #ifdef SVR3
  2112.     prtopt(" SVR3");
  2113. #endif /* SVR3 */
  2114. #ifdef SVR4
  2115.     prtopt(" SVR4");
  2116. #endif /* SVR4 */
  2117. #ifdef DELL_SVR4
  2118.     prtopt(" DELL_SVR4");
  2119. #endif /* DELL_SVR4 */
  2120. #ifdef ICL_SVR4
  2121.     prtopt(" ICL_SVR4");
  2122. #endif /* ICL_SVR4 */
  2123. #ifdef OSF
  2124.     prtopt(" OSF");
  2125. #endif /* OSF */
  2126. #ifdef PTX
  2127.     prtopt(" PTX");
  2128. #endif /* PTX */
  2129. #ifdef POSIX
  2130.     prtopt(" POSIX");
  2131. #endif /* POSIX */
  2132. #ifdef SOLARIS
  2133.     prtopt(" SOLARIS");
  2134. #endif /* SOLARIS */
  2135. #ifdef SUNOS4
  2136.     prtopt(" SUNOS4");
  2137. #endif /* SUNOS4 */
  2138. #ifdef SUN4S5
  2139.     prtopt(" SUN4S5");
  2140. #endif /* SUN4S5 */
  2141. #ifdef ENCORE
  2142.     prtopt(" ENCORE");
  2143. #endif /* ENCORE */
  2144. #ifdef ultrix
  2145.     prtopt(" ultrix");
  2146. #endif
  2147. #ifdef sxaE50
  2148.     prtopt(" sxaE50");
  2149. #endif
  2150. #ifdef mips
  2151.     prtopt(" mips");
  2152. #endif
  2153. #ifdef MIPS
  2154.     prtopt(" MIPS");
  2155. #endif
  2156. #ifdef vax
  2157.     prtopt(" vax");
  2158. #endif
  2159. #ifdef VAX
  2160.     prtopt(" VAX");
  2161. #endif
  2162. #ifdef __ALPHA
  2163.     prtopt(" __ALPHA");
  2164. #endif
  2165. #ifdef sun
  2166.     prtopt(" sun");
  2167. #endif
  2168. #ifdef sun3
  2169.     prtopt(" sun3");
  2170. #endif
  2171. #ifdef sun386
  2172.     prtopt(" sun386");
  2173. #endif
  2174. #ifdef _SUN
  2175.     prtopt(" _SUN");
  2176. #endif
  2177. #ifdef sun4
  2178.     prtopt(" sun4");
  2179. #endif
  2180. #ifdef sparc
  2181.     prtopt(" sparc");
  2182. #endif
  2183. #ifdef _CRAY
  2184.     prtopt(" _CRAY");
  2185. #endif /* _CRAY */
  2186. #ifdef NEXT
  2187.     prtopt(" NEXT");
  2188. #endif
  2189. #ifdef NEXT3
  2190.     prtopt(" NEXT3");
  2191. #endif /* NEXT3 */
  2192. #ifdef NeXT
  2193.     prtopt(" NeXT");
  2194. #endif
  2195. #ifdef sgi
  2196.     prtopt(" sgi");
  2197. #endif
  2198. #ifdef M_SYS5
  2199.     prtopt(" M_SYS5");
  2200. #endif
  2201. #ifdef __SYSTEM_FIVE
  2202.     prtopt(" __SYSTEM_FIVE");
  2203. #endif
  2204. #ifdef sysV
  2205.     prtopt(" sysV");
  2206. #endif
  2207. #ifdef M_XENIX                /* SCO Xenix V and UNIX/386 */
  2208.     prtopt(" M_XENIX");
  2209. #endif 
  2210. #ifdef M_UNIX                /* SCO UNIX */
  2211.     prtopt(" M_UNIX");
  2212. #endif
  2213. #ifdef _M_UNIX                /* SCO UNIX 3.2v4 = ODT 2.0 */
  2214.     prtopt(" _M_UNIX");
  2215. #endif
  2216. #ifdef M_I586
  2217.     prtopt(" M_I586");
  2218. #endif
  2219. #ifdef _M_I586
  2220.     prtopt(" _M_I586");
  2221. #endif
  2222. #ifdef i586
  2223.     prtopt(" i586");
  2224. #endif
  2225. #ifdef M_I486
  2226.     prtopt(" M_I486");
  2227. #endif
  2228. #ifdef _M_I486
  2229.     prtopt(" _M_I486");
  2230. #endif
  2231. #ifdef i486
  2232.     prtopt(" i486");
  2233. #endif
  2234. #ifdef M_I386
  2235.     prtopt(" M_I386");
  2236. #endif
  2237. #ifdef _M_I386
  2238.     prtopt(" _M_I386");
  2239. #endif
  2240. #ifdef i386
  2241.     prtopt(" i386");
  2242. #endif
  2243. #ifdef i286
  2244.     prtopt(" i286");
  2245. #endif
  2246. #ifdef M_I286
  2247.     prtopt(" M_I286");
  2248. #endif
  2249. #ifdef mc68000
  2250.     prtopt(" mc68000");
  2251. #endif
  2252. #ifdef mc68010
  2253.     prtopt(" mc68010");
  2254. #endif
  2255. #ifdef mc68020
  2256.     prtopt(" mc68020");
  2257. #endif
  2258. #ifdef mc68030
  2259.     prtopt(" mc68030");
  2260. #endif
  2261. #ifdef mc68040
  2262.     prtopt(" mc68040");
  2263. #endif
  2264. #ifdef M_68000
  2265.     prtopt(" M_68000");
  2266. #endif
  2267. #ifdef M_68010
  2268.     prtopt(" M_68010");
  2269. #endif
  2270. #ifdef M_68020
  2271.     prtopt(" M_68020");
  2272. #endif
  2273. #ifdef M_68030
  2274.     prtopt(" M_68030");
  2275. #endif
  2276. #ifdef M_68040
  2277.     prtopt(" M_68040");
  2278. #endif
  2279. #ifdef m68k
  2280.     prtopt(" m68k");
  2281. #endif
  2282. #ifdef m88k
  2283.     prtopt(" m88k");
  2284. #endif
  2285. #ifdef pdp11
  2286.     prtopt(" pdp11");
  2287. #endif
  2288. #ifdef iAPX
  2289.     prtopt(" iAPX");
  2290. #endif
  2291. #ifdef __hp9000s800
  2292.     prtopt(" __hp9000s800");
  2293. #endif
  2294. #ifdef __hp9000s500
  2295.     prtopt(" __hp9000s500");
  2296. #endif
  2297. #ifdef __hp9000s300
  2298.     prtopt(" __hp9000s300");
  2299. #endif
  2300. #ifdef __hp9000s200
  2301.     prtopt(" __hp9000s200");
  2302. #endif
  2303. #ifdef AIX
  2304.     prtopt(" AIX");
  2305. #endif
  2306. #ifdef _AIXFS
  2307.     prtopt(" _AIXFS");
  2308. #endif
  2309. #ifdef u370
  2310.     prtopt(" u370");
  2311. #endif
  2312. #ifdef u3b
  2313.     prtopt(" u3b");
  2314. #endif
  2315. #ifdef u3b2
  2316.     prtopt(" u3b2");
  2317. #endif
  2318. #ifdef multimax
  2319.     prtopt(" multimax");
  2320. #endif
  2321. #ifdef balance
  2322.     prtopt(" balance");
  2323. #endif
  2324. #ifdef ibmrt
  2325.     prtopt(" ibmrt");
  2326. #endif
  2327. #ifdef _IBMRT
  2328.     prtopt(" _IBMRT");
  2329. #endif
  2330. #ifdef ibmrs6000
  2331.     prtopt(" ibmrs6000");
  2332. #endif
  2333. #ifdef _AIX
  2334.     prtopt(" _AIX");
  2335. #endif /* _AIX */
  2336. #ifdef _IBMR2
  2337.     prtopt(" _IBMR2");
  2338. #endif
  2339. #ifdef QNX
  2340.     prtopt(" QNX");
  2341. #endif
  2342. #ifdef __STRICT_BSD__
  2343.     prtopt(" __STRICT_BSD__");
  2344. #endif
  2345. #ifdef __STRICT_ANSI__
  2346.     prtopt(" __STRICT_ANSI__");
  2347. #endif
  2348. #ifdef _ANSI_C_SOURCE
  2349.     prtopt(" _ANSI_C_SOURCE");
  2350. #endif
  2351. #ifdef __STDC__
  2352.     prtopt(" __STDC__");
  2353. #endif
  2354. #ifdef __DECC
  2355.     prtopt(" __DECC");
  2356. #endif
  2357. #ifdef __GNUC__                /* gcc in ansi mode */
  2358.     prtopt(" __GNUC__");
  2359. #endif
  2360. #ifdef GNUC                /* gcc in traditional mode */
  2361.     prtopt(" GNUC");
  2362. #endif
  2363. #ifdef CK_ANSIC
  2364.     prtopt(" CK_ANSIC");
  2365. #endif
  2366. #ifdef CK_ANSILIBS
  2367.     prtopt(" CK_ANSILIBS");
  2368. #endif
  2369. #ifdef _XOPEN_SOURCE
  2370.     prtopt(" _XOPEN_SOURCE");
  2371. #endif
  2372. #ifdef _ALL_SOURCE
  2373.     prtopt(" _ALL_SOURCE");
  2374. #endif
  2375. #ifdef _SC_JOB_CONTROL
  2376.     prtopt(" _SC_JOB_CONTROL");
  2377. #endif
  2378. #ifdef _POSIX_JOB_CONTROL
  2379.     prtopt(" _POSIX_JOB_CONTROL");
  2380. #endif
  2381. #ifdef SVR3JC
  2382.     prtopt(" SVR3JC");
  2383. #endif
  2384. #ifdef _386BSD
  2385.     prtopt(" _386BSD");
  2386. #endif
  2387. #ifdef _BSD
  2388.     prtopt(" _BSD");
  2389. #endif
  2390. #ifdef TERMIOX
  2391.     prtopt(" TERMIOX");
  2392. #endif /* TERMIOX */
  2393. #ifdef STERMIOX
  2394.     prtopt(" STERMIOX");
  2395. #endif /* STERMIOX */
  2396. #ifdef CK_CURSES
  2397.     prtopt(" CK_CURSES");
  2398. #endif /* CK_CURSES */
  2399. #ifdef CK_DTRCD
  2400.     prtopt(" CK_DTRCD");
  2401. #endif /* CK_DTRCD */
  2402. #ifdef CK_DTRCTS
  2403.     prtopt(" CK_DTRCTS");
  2404. #endif /* CK_DTRCTS */
  2405. #ifdef CK_RTSCTS
  2406.     prtopt(" CK_RTSCTS");
  2407. #endif /* CK_RTSCTS */
  2408.     prtopt((char *)0);
  2409.     printf("\n\n");
  2410. }
  2411. #endif /* NOFRILLS */
  2412.  
  2413. #ifdef VMS
  2414. VOID
  2415. sholbl() {
  2416.     printf("VMS Labeled File Features:\n");
  2417.     printf(" acl %s (ACL info %s)\n",
  2418.        lf_opts & LBL_ACL ? "on " : "off",
  2419.        lf_opts & LBL_ACL ? "preserved" : "discarded");
  2420.     printf(" backup-date %s (backup date/time %s)\n",
  2421.        lf_opts & LBL_BCK ? "on " : "off",
  2422.        lf_opts & LBL_BCK ? "preserved" : "discarded");
  2423.     printf(" name %s (original filename %s)\n",
  2424.        lf_opts & LBL_NAM ? "on " : "off",
  2425.        lf_opts & LBL_NAM ? "preserved" : "discarded");
  2426.     printf(" owner %s (original file owner id %s)\n",
  2427.        lf_opts & LBL_OWN ? "on " : "off",
  2428.        lf_opts & LBL_OWN ? "preserved" : "discarded");
  2429.     printf(" path %s (original file's disk:[directory] %s)\n",
  2430.        lf_opts & LBL_PTH ? "on " : "off",
  2431.        lf_opts & LBL_PTH ? "preserved" : "discarded");
  2432. }
  2433. #endif /* VMS */
  2434.  
  2435. VOID
  2436. shotcs(cs1,cs2) int cs1, cs2; {        /* Show terminal character set */
  2437. #ifndef NOCSETS
  2438. #ifndef MAC
  2439.     int y;
  2440.     char *s;
  2441. #ifdef CK_ANSIC
  2442.     int gettcs(int, int);
  2443. #else
  2444.     int gettcs();
  2445. #endif /* CK_ANSIC */
  2446.  
  2447.     printf(" Terminal character-set");
  2448.     if (cs1 == cs2) {
  2449.     printf(": transparent\n");
  2450.     } else {
  2451.     s = "unknown";
  2452. #ifdef COMMENT /* old dumb way */
  2453.     for (y = 0; y <= nfilc; y++)    /* Look up name in keyword table */
  2454.       if (ttcstab[y].kwval == cs2) {
  2455.           if (ttcstab[y].flgs & CM_INV) /* Skip synonyms */
  2456.         continue;
  2457.           s = ttcstab[y].kwd;
  2458.           break;
  2459.       }
  2460.     printf("s:\n   Remote: %s\n   Local:  ",s);
  2461.     s = "unknown";
  2462.     for (y = 0; y <= nfilc; y++)
  2463.       if (ttcstab[y].kwval == cs1) {
  2464.         if (ttcstab[y].flgs & CM_INV) /* Skip synonyms */
  2465.           continue;
  2466.         s = ttcstab[y].kwd;
  2467.           break;
  2468.       }
  2469.     printf("%s",s);
  2470. #else
  2471.     printf("s:\n   Remote: %s\n   Local:  %s",
  2472.            fcsinfo[cs2].keyword,fcsinfo[cs1].keyword);
  2473. #endif /* COMMENT */
  2474.     if (cs2 != cs1) {
  2475.         switch(gettcs(cs2,cs1)) {
  2476.           case TC_USASCII:  s = "ascii";        break;
  2477.           case TC_1LATIN:   s = "latin1-iso";   break;
  2478.           case TC_2LATIN:   s = "latin2-iso";   break;
  2479.           case TC_CYRILL:   s = "cyrillic-iso"; break;
  2480.           case TC_JEUC:     s = "japanese-euc"; break;
  2481.           case TC_HEBREW:   s = "hebrew-iso";   break;
  2482.           default:          s = "transparent";  break;
  2483.         }
  2484.         printf("\n   Via:    %s\n",s);
  2485.     }
  2486.     }
  2487. #endif /* MAC */
  2488. #endif /* NOCSETS */
  2489. }
  2490. #endif /* NOSHOW */
  2491.  
  2492. #ifndef NOSHOW
  2493. int
  2494. doshow(x) int x; {
  2495.     int y, i; long zz;
  2496.     char *s;
  2497.  
  2498. #ifndef NOSETKEY
  2499.     if (x == SHKEY) {            /* SHOW KEY */
  2500.     int c;
  2501.     KEY ch;
  2502.     CHAR *s;
  2503.  
  2504.     if ((y = cmcfm()) < 0) return(y);        
  2505. #ifdef MAC
  2506.     printf("Not implemented\n");
  2507.     return(0);
  2508. #else /* Not MAC */
  2509.     printf(" Press key: ");
  2510. #ifdef UNIX
  2511. #ifdef NOSETBUF
  2512.     fflush(stdout);
  2513. #endif /* NOSETBUF */
  2514. #endif /* UNIX */
  2515.     conbin((char)escape);        /* Put terminal in binary mode */
  2516.     c = congks(0);            /* Get character or scan code */
  2517.     concb((char)escape);        /* Restore terminal to cbreak mode */
  2518.     if (c < 0) {            /* Check for error */
  2519.         printf("?Error reading key\n");
  2520.         return(0);
  2521.     }
  2522. #ifndef OS2
  2523. /*
  2524.   Do NOT mask when it can be a raw scan code, perhaps > 255
  2525. */
  2526.     c &= cmdmsk;            /* Apply command mask */
  2527. #endif /* OS2 */
  2528.     printf("\n Key code \\%d => ",c);
  2529.         if (macrotab[c]) {        /* See if there's a macro */
  2530.         printf("String: ");        /* If so, display its definition */
  2531.             s = macrotab[c];
  2532.         while (ch = *s++)
  2533.           if (ch < 32 || ch == 127
  2534. /*
  2535.   Systems whose native character sets have graphic characters in C1...
  2536. */
  2537. #ifndef NEXT                /* NeXT */
  2538. #ifndef AUX                /* Macintosh */
  2539. #ifndef XENIX                /* IBM PC */
  2540. #ifndef OS2                /* IBM PC */
  2541.           || (ch > 127 && ch < 160)
  2542. #endif /* OS2 */
  2543. #endif /* XENIX */
  2544. #endif /* AUX */
  2545. #endif /* NEXT */
  2546.           )
  2547.                 printf("\\{%d}",ch);    /* Display control characters */
  2548.           else putchar((char) ch);    /* in backslash notation */
  2549.         printf("\n");
  2550.         } else {            /* No macro, show single character */
  2551.         printf("Character: ");
  2552.         ch = keymap[c];
  2553.         if (ch < 32 || ch == 127 || ch > 255
  2554. #ifndef NEXT
  2555. #ifndef AUX
  2556. #ifndef XENIX
  2557. #ifndef OS2
  2558.           || (ch > 127 && ch < 160)
  2559. #endif /* OS2 */
  2560. #endif /* XENIX */
  2561. #endif /* AUX */
  2562. #endif /* NEXT */
  2563.         )
  2564. /*
  2565.   These used to be %d, but gcc 1.93 & later complain about type mismatches.
  2566.   %u is supposed to be totally portable.
  2567. */
  2568.           printf("\\%u",(unsigned int) ch);
  2569.         else printf("%c \\%u",(CHAR) ch,(unsigned int) ch);
  2570.     }
  2571.     if (ch == (KEY) c)
  2572.       printf(" (self, no translation)\n");
  2573.     else printf("\n");
  2574.     return(1);
  2575. #endif /* MAC */
  2576.     }
  2577. #endif /* NOSETKEY */
  2578.  
  2579. #ifndef NOSPL
  2580.     if (x == SHMAC) {            /* SHOW MACRO */
  2581.     x = cmfld("Macro name, or carriage return to see them all","",&s,
  2582.           NULL);
  2583.     if (x == -3)            /* This means they want see all */
  2584.       *line = '\0';
  2585.     else if (x < 0)            /* Otherwise negative = parse error */
  2586.       return(x);
  2587.     else                /* 0 or greater */
  2588.       strcpy(line,s);        /* means they typed something */
  2589.     if ((y = cmcfm()) < 0) return(y); /* Get confirmation */
  2590.     if (*line) {
  2591.         slc = 0;            /* Initial SHO MAC line number */
  2592.         x = mlook(mactab,s,nmac);    /* Look up what they typed */
  2593.         switch (x) {
  2594.           case -3:            /* Nothing to look up */
  2595.         return(0);
  2596.           case -1:            /* Not found */
  2597.         printf("%s - not found\n",s);
  2598.         return(0);
  2599.           case -2:            /* Ambiguous, matches more than one */
  2600.         y = (int)strlen(line);
  2601.         slc = 1;
  2602.         for (x = 0; x < nmac; x++)
  2603.           if (!strncmp(mactab[x].kwd,line,y))
  2604.             if (shomac(mactab[x].kwd,mactab[x].mval) < 0) break;
  2605.         return(1);
  2606.           default:            /* Matches one exactly */
  2607.         shomac(mactab[x].kwd,mactab[x].mval);
  2608.         return(1);
  2609.         }
  2610.     } else {            /* They want to see them all */
  2611.         printf("Macros:\n");
  2612.         slc = 1;
  2613.         for (y = 0; y < nmac; y++)
  2614.           if (shomac(mactab[y].kwd,mactab[y].mval) < 0) break;
  2615.         return(1);
  2616.     }
  2617.     }
  2618. #endif /* NOSPL */
  2619.  
  2620. /*
  2621.   Other SHOW commands only have two fields.  Get command confirmation here,
  2622.   then handle with big switch() statement.
  2623. */
  2624.     if ((y = cmcfm()) < 0) return(y);
  2625.     switch (x) {
  2626.  
  2627. #ifdef SUNX25
  2628.         case SHPAD:
  2629.             shopad();
  2630.             break;
  2631. #endif /* SUNX25 */
  2632.  
  2633. #ifdef NETCONN
  2634.     case SHNET:
  2635.         shonet();
  2636.         break;
  2637. #endif /* NETCONN */
  2638.  
  2639.     case SHPAR:
  2640.         shopar();
  2641.         break;
  2642.  
  2643.         case SHATT:
  2644.         shoatt();
  2645.         break;
  2646.  
  2647. #ifndef NOSPL
  2648.     case SHCOU:
  2649.         printf(" %d\n",count[cmdlvl]);
  2650.         break;
  2651. #endif /* NOSPL */
  2652.  
  2653. #ifndef NOSERVER
  2654.         case SHSER:            /* Show Server */
  2655. #ifndef NOFRILLS
  2656.         printf("Function           Status:\n");
  2657.         printf(" GET                %s\n",nm[en_get]);
  2658.         printf(" SEND               %s\n",nm[en_sen]);        
  2659.         printf(" REMOTE CD/CWD      %s\n",nm[en_cwd]);
  2660.         printf(" REMOTE DELETE      %s\n",nm[en_del]);
  2661.         printf(" REMOTE DIRECTORY   %s\n",nm[en_dir]);
  2662.         printf(" REMOTE HOST        %s\n",nm[en_hos]);        
  2663.         printf(" REMOTE SET         %s\n",nm[en_set]);        
  2664.         printf(" REMOTE SPACE       %s\n",nm[en_spa]);        
  2665.         printf(" REMOTE TYPE        %s\n",nm[en_typ]);        
  2666.         printf(" REMOTE WHO         %s\n",nm[en_who]);
  2667.         printf(" BYE                %s\n",nm[en_bye]);
  2668.             printf(" FINISH             %s\n",nm[en_fin]);
  2669. #endif /* NOFRILLS */
  2670.         printf("Server timeout: %d\n",srvtim);
  2671.         printf("Server display: %s\n\n", srvdis ? "on" : "off");
  2672.         break;
  2673. #endif /* NOSERVER */
  2674.  
  2675.         case SHSTA:            /* Status of last command */
  2676.         printf( " %s\n", success ? "SUCCESS" : "FAILURE" );
  2677.         return(0);            /* Don't change it */
  2678.  
  2679. #ifdef MAC
  2680.     case SHSTK: {            /* Stack for MAC debugging */
  2681.         long sp;
  2682.  
  2683.         sp = -1;
  2684.         loadA0 ((char *)&sp);    /* set destination address */
  2685.         SPtoaA0();            /* move SP to destination */
  2686.         printf("Stack at 0x%x\n", sp);
  2687.         show_queue();        /* more debugging */
  2688.         break; 
  2689.     }
  2690. #endif /* MAC */
  2691.  
  2692.     case SHTER:
  2693.         printf(" Command bytesize:  %d bits\n",
  2694.            (cmdmsk == 0377) ? 8 : 7);
  2695.         printf(" Terminal bytesize: %d bits\n",
  2696.            (cmask == 0377) ? 8 : 7);
  2697. #ifdef OS2
  2698.         printf(" Terminal type: %s\n",
  2699.            (tt_type == TT_VT102) ? "VT102" : "VT52");
  2700.  
  2701. #endif /* OS2 */
  2702.         printf(" Terminal echo: %s\n", duplex ? "local" : "remote");
  2703.         printf(" Terminal locking-shift: %s\n", sosi ? "on" : "off");
  2704.         printf(" Terminal newline-mode:  %s\n", tnlm ? "on" : "off");
  2705.         printf(" Terminal cr-display:    %s\n",
  2706.            tt_crd ? "crlf" : "normal");
  2707. #ifdef OS2
  2708. /* Should show cursor and colors here too... */
  2709.         printf(" Terminal arrow-keys:    %s\n",
  2710.            tt_arrow ? "cursor" : "application");
  2711.         printf(" Terminal keypad-mode:   %s\n",
  2712.            tt_keypad ? "numeric" : "application");
  2713.         printf(" Terminal answerback:    %s\n",
  2714.            tt_answer ? "on" : "off");
  2715.         printf(" Terminal wrap:          %s\n",
  2716.            tt_wrap ? "on" : "off");
  2717.         printf(" Scrollback buffer size: %d\n", tt_scrsize);
  2718. #endif /* OS2 */
  2719.  
  2720. #ifndef NOCSETS
  2721.         shotcs(tcsl,tcsr);
  2722. #endif /* NOCSETS */
  2723.         printf(" CONNECT-mode escape character: %d (Ctrl-%c, %s)\n",
  2724.          escape,ctl(escape),(escape == 127 ? "DEL" : ccntab[escape]));
  2725. #ifdef UNIX
  2726.         printf(" Suspend: %s\n", suspend ? "on" : "off");
  2727. #endif /* UNIX */
  2728.         break;
  2729.  
  2730. #ifndef NOFRILLS
  2731.     case SHVER:
  2732.         shover();
  2733.         break;
  2734. #endif /* NOFRILLS */
  2735.  
  2736. #ifndef NOSPL
  2737.     case SHBUI:            /* Built-in variables */
  2738.         i = 0;
  2739.         for (y = 0; y < nvars; y++) {
  2740.         printf(" \\v(%s) = %s\n",vartab[y].kwd,nvlook(vartab[y].kwd));
  2741.         if (++i > SCRNLEN) {    /* More than a screenful... */
  2742.             if (!askmore())
  2743.               break;
  2744.             else
  2745.               i = 0;
  2746.         }
  2747.         }
  2748.             break;
  2749.  
  2750.     case SHFUN:            /* Functions */
  2751.         for (y = 0; y < nfuncs; y++)
  2752.           printf(" \\f%s()\n",fnctab[y].kwd);
  2753.         break;
  2754.  
  2755.         case SHVAR:            /* Global variables */
  2756.         x = 0;            /* Variable count */
  2757.         slc = 1;            /* Screen line count for "more?" */
  2758.         for (y = 33; y < GVARS; y++)
  2759.           if (g_var[y]) {
  2760.           if (x++ == 0) printf("Global variables:\n");
  2761.           sprintf(line," \\%%%c",y);
  2762.           if (shomac(line,g_var[y]) < 0) break;
  2763.           }
  2764.         if (!x) printf(" No variables defined\n");
  2765.         break;
  2766.  
  2767.         case SHARG:            /* Args */
  2768.         if (maclvl > -1) {
  2769.         printf("Macro arguments at level %d\n",maclvl);
  2770.         for (y = 0; y < 10; y++)
  2771.           if (m_arg[maclvl][y])
  2772.             printf(" \\%%%d = %s\n",y,m_arg[maclvl][y]);
  2773.         } else {
  2774.         printf(" No macro arguments at top level\n");
  2775.         }
  2776.         break;
  2777.  
  2778.         case SHARR:            /* Arrays */
  2779.         x = 0;
  2780.         for (y = 0; y < 27; y++)
  2781.           if (a_ptr[y]) {
  2782.           if (x == 0) printf("Declared arrays:\n");
  2783.           x = 1;
  2784.           printf(" \\&%c[%d]\n",(y == 0) ? 64 : y + 96, a_dim[y]);
  2785.           }
  2786.         if (!x) printf(" No arrays declared\n");
  2787.         break;
  2788. #endif /* NOSPL */
  2789.  
  2790.     case SHPRO:            /* Protocol parameters */
  2791.         shoparp();
  2792. #ifdef XFRCAN
  2793.         printf("\n Cancellation: %s",xfrcan ? "on" : "off");
  2794.         if (xfrcan) printf(" %d %d\n", xfrchr, xfrnum);
  2795.         else printf("\n");
  2796. #endif /* XFRCAN */
  2797.         printf("\n");
  2798.         break;
  2799.  
  2800.     case SHCOM:            /* Communication parameters */
  2801.         printf("\n");
  2802.         shoparc();
  2803. #ifndef NODIAL
  2804.         printf("\n");
  2805. #ifdef NETCONN
  2806.         if (!network)
  2807. #endif /* NETCONN */
  2808.           shodial();
  2809. #endif /* NODIAL */
  2810.         printf("\n");
  2811.         shomdm();
  2812.         printf("\n");
  2813.         break;
  2814.  
  2815.     case SHFIL:            /* File parameters */
  2816.         shoparf();
  2817.         printf("\n");
  2818.         break;
  2819.  
  2820. #ifndef NOCSETS
  2821.     case SHLNG:            /* Languages */
  2822.         shoparl();
  2823.         break;
  2824. #endif /* NOCSETS */
  2825.  
  2826. #ifndef NOSPL
  2827.     case SHSCR:            /* Scripts */
  2828.         printf(" Take  Echo:     %s\n", techo  ? "On" : "Off");
  2829.         printf(" Take  Error:    %s\n", takerr[cmdlvl] ? "On" : "Off");
  2830.         printf(" Macro Echo:     %s\n", mecho  ? "On" : "Off");
  2831.         printf(" Macro Error:    %s\n", merror[cmdlvl] ? "On" : "Off");
  2832.         printf(" Input Case:     %s\n", inpcas[cmdlvl] ?
  2833.            "Observe" : "Ignore");
  2834.         printf(" Input Echo:     %s\n", inecho ? "On" : "Off");
  2835.             printf(" Input Silence:  %d (seconds)\n", insilence);
  2836.         printf(" Input Timeout:  %s\n", intime[cmdlvl] ?
  2837.            "Quit" : "Proceed");
  2838.         printf(" Output Pacing:  %d (milliseconds)\n",pacing);
  2839. #ifndef NOSCRIPT
  2840.         printf(" Script Echo:    %s\n", secho  ? "On" : "Off");
  2841. #endif /* NOSCRIPT */
  2842.         break;
  2843. #endif /* NOSPL */
  2844.  
  2845. #ifndef NOXMIT
  2846.       case SHXMI:
  2847.         printf(" File type: %s\n", binary ? "binary" : "text");
  2848. #ifndef NOCSETS
  2849.         shotcs(tcsl,tcsr);
  2850. #endif /* NOCSETS */
  2851.         printf(" Terminal echo: %s\n", duplex ? "local" : "remote");
  2852.             printf(" Transmit EOF: ");
  2853.         if (*xmitbuf == NUL) {
  2854.         printf("none\n");
  2855.         } else {
  2856.         char *p;
  2857.         p = xmitbuf;
  2858.         while (*p) {
  2859.             if (*p < SP)
  2860.               printf("^%c",ctl(*p));
  2861.             else
  2862.               printf("%c",*p);
  2863.             p++;
  2864.         }
  2865.         printf("\n");
  2866.         }
  2867.         if (xmitf)
  2868.           printf(" Transmit Fill: %d (fill character for blank lines)\n",
  2869.            xmitf);
  2870.         else printf(" Transmit Fill: none\n");
  2871.         printf(" Transmit Linefeed: %s\n",
  2872.            xmitl ? "on (send linefeeds too)" : "off");
  2873.         if (xmitp) 
  2874.           printf(" Transmit Prompt: %d (host line end character)\n",xmitp);
  2875.         else printf(" Transmit Prompt: none\n");
  2876.         printf(" Transmit Echo: %s\n",
  2877.            xmitx ? "on" : "off");
  2878.         printf(" Transmit Locking-Shift: %s\n",xmits ? "on" : "off");
  2879.         printf(" Transmit Pause: %d milliseconds\n", xmitw);
  2880.         break;
  2881. #endif /* NOXMIT */
  2882.  
  2883.       case SHMOD:            /* SHOW MODEM */
  2884.         shmdmlin();
  2885.         printf("\n");
  2886.         shomdm();
  2887.         break;
  2888.  
  2889. #ifndef MAC
  2890.           case SHDFLT:
  2891.         zsyscmd(PWDCMD);
  2892.             break;
  2893. #endif /* MAC */
  2894.  
  2895.           case SHESC:
  2896.         printf(" Escape character: Ctrl-%c (ASCII %d, %s)\r\n",
  2897.            ctl(escape), escape, (escape == 127 ? "DEL" : ccntab[escape]));
  2898.         break;
  2899.  
  2900. #ifndef NODIAL
  2901.       case SHDIA:
  2902.         shmdmlin();
  2903.         printf(", speed: ");
  2904.         if ((zz = ttgspd()) < 0) {
  2905.         printf("unknown\n");
  2906.         } else {
  2907.         if (zz == 8880) printf("75/1200\n"); else printf("%ld\n",zz);
  2908.         }
  2909.         doshodial();
  2910.         if (carrier == CAR_OFF) s = "off";
  2911.         else if (carrier == CAR_ON) s = "on";
  2912.         else if (carrier == CAR_AUT) s = "auto";
  2913.         else s = "unknown";
  2914.         printf(" Carrier: %s", s);
  2915.         if (carrier == CAR_ON) {
  2916.         if (cdtimo) printf(", timeout: %d sec", cdtimo);
  2917.         else printf(", timeout: none");
  2918.         }
  2919.         if (local
  2920. #ifdef NETCONN
  2921.         && !network
  2922. #endif /* NETCONN */
  2923.         ) {
  2924.         printf("\n%s modem signals:\n",ttname);
  2925.         shomdm();
  2926.         } else printf("\n");
  2927.         break;
  2928. #endif /* NODIAL */
  2929.  
  2930. #ifdef VMS
  2931.     case SHLBL:            /* Labeled file info */
  2932.         sholbl();
  2933.         break;
  2934. #endif /* VMS */        
  2935.  
  2936.     case SHCSE:            /* Character sets */
  2937. #ifdef NOCSETS
  2938.         printf(
  2939. " Character set translation is not supported in this version of C-Kermit\n");
  2940. #else
  2941.         shocharset();
  2942.             printf("\n Unknown-Char-Set: %s\n",
  2943.            unkcs ? "Keep" : "Discard");
  2944.         shotcs(tcsl,tcsr);
  2945.         printf("\n");
  2946. #endif /* NOCSETS */
  2947.         break;
  2948.  
  2949. #ifndef NOFRILLS
  2950.       case SHFEA:            /* Features */
  2951.         shofea();
  2952.         break;
  2953. #endif /* NOFRILLS */
  2954.  
  2955. #ifdef CK_SPEED
  2956.       case SHCTL:            /* Control-Prefix table */
  2957.         shoctl();
  2958.         break;
  2959. #endif /* CK_SPEED */
  2960.  
  2961.     default:
  2962.         printf("\nNothing to show...\n");
  2963.         return(-2);
  2964.     }
  2965.     return(success = 1);
  2966. }
  2967.  
  2968. VOID
  2969. shmdmlin() {                /* Briefly show modem & line */
  2970.     int i;
  2971. #ifndef NODIAL
  2972. #ifndef MINIDIAL
  2973.     extern int tbmodel;
  2974.     _PROTOTYP( char * gtbmodel, (void) );
  2975. #endif /* MINIDIAL */
  2976. #endif /* NODIAL */
  2977.     if (local)
  2978.       printf(" Line: %s, Modem: ",ttname);
  2979.     else
  2980.       printf(" Communication device not yet selected with SET LINE\n Modem: ");
  2981. #ifndef NODIAL
  2982.     for (i = 0; i < nmdm; i++) {
  2983.     if (mdmtab[i].kwval == mdmtyp) {
  2984.         if (!strcmp(mdmtab[i].kwd,"courier"))
  2985.           printf("courier or sportster");
  2986.         else
  2987.           printf("%s",mdmtab[i].kwd);
  2988.         break;
  2989.     }
  2990.     }
  2991. #ifndef MINIDIAL
  2992.     if (tbmodel) printf(" (%s)",gtbmodel()); /* Telebit model info */
  2993. #endif /* MINIDIAL */
  2994. #else
  2995.     printf("(disabled)");
  2996. #endif /* NODIAL */
  2997. }
  2998. #endif /* NOSHOW */
  2999.  
  3000. #ifdef GEMDOS
  3001. isxdigit(c) int c; {
  3002.     return(isdigit(c) ||
  3003.        (c >= 'a' && c <= 'f') ||
  3004.        (c >= 'A' && c <= 'F'));
  3005. }
  3006. #endif /* GEMDOS */
  3007.  
  3008. #ifndef NOSHOW
  3009. #ifndef NOSPL
  3010. int                    /* SHO MACROS */
  3011. shomac(s1, s2) char *s1, *s2; {
  3012.     int x, n, pp;
  3013.     pp = 0;                /* Parenthesis counter */
  3014.  
  3015.     if (!s1)
  3016.       return(0);
  3017.     else
  3018.       printf("\n%s = ",s1);        /* Print blank line and macro name */
  3019.     slc++;                /* Count the line */
  3020.     n = (int)strlen(s1) + 4;        /* Width of current line */
  3021.     if (!s2) s2 = "(null definition)";
  3022.  
  3023.     while (x = *s2++) {            /* Loop thru definition */
  3024.     if (x == '(') pp++;        /* Treat commas within parens */
  3025.     if (x == ')') pp--;        /* as ordinary text */
  3026.     if (pp < 0) pp = 0;        /* Outside parens, */
  3027.     if (x == ',' && pp == 0) {    /* comma becomes comma-dash-NL. */
  3028.         putchar(',');
  3029.         putchar('-');
  3030.         x = '\n';
  3031.     }
  3032.     putchar(x);            /* Output the character */
  3033.     if (x == '\n') {        /* If it was a newline */
  3034. #ifdef UNIX
  3035. #ifdef NOSETBUF
  3036.         fflush(stdout);
  3037. #endif /* NOSETBUF */
  3038. #endif /* UNIX */
  3039.         putchar(' ');        /* Indent the next line 1 space */
  3040.         while(*s2 == ' ') s2++;    /* skip past leading blanks */
  3041.         n = 2;            /* restart the character counter */
  3042.         slc++;            /* and increment the line counter. */
  3043.     } else if (++n > SCRNWID) {    /* If line is too wide */
  3044.         putchar('-');        /* output a dash */
  3045.         putchar(NL);        /* and a newline */
  3046. #ifdef UNIX
  3047. #ifdef NOSETBUF
  3048.         fflush(stdout);
  3049. #endif /* NOSETBUF */
  3050. #endif /* UNIX */
  3051.         n = 1;            /* and restart the char counter */
  3052.         slc++;            /* and increment the line counter */
  3053.     }
  3054.     if (n < 3 && slc > SCRNLEN) {    /* If new line and screen is full */
  3055.         if (!askmore()) return(-1);    /* ask if they want more. */
  3056.         n = 1;            /* They do, start a new line */
  3057.         slc = 0;            /* and restart line counter */
  3058.     }
  3059.     }
  3060.     putchar(NL);            /* End of definition */
  3061.     if (++slc > SCRNLEN) {
  3062.     if (!askmore()) return(-1);
  3063.     slc = 0;
  3064.     }
  3065.     return(0);
  3066. }
  3067. #endif /* NOSPL */
  3068. #endif /* NOSHOW */
  3069.  
  3070. #ifndef NOSHOW
  3071. int
  3072. shoatt() {
  3073.     printf("Attributes: %s\n", atcapr ? "On" : "Off");
  3074.     if (!atcapr) return(0);
  3075.     printf(" Blocksize: %s\n", atblki ? "On" : "Off");
  3076.     printf(" Date: %s\n", atdati ? "On" : "Off");
  3077.     printf(" Disposition: %s\n", atdisi ? "On" : "Off");
  3078.     printf(" Encoding (Character Set): %s\n", atenci ? "On" : "Off");
  3079.     printf(" Length: %s\n", atleni ? "On" : "Off");
  3080.     printf(" Type (text/binary): %s\n", attypi ? "On" : "Off");
  3081.     printf(" System ID: %s\n", atsidi ? "On" : "Off");
  3082.     printf(" System Info: %s\n", atsysi ? "On" : "Off");
  3083.     return(0);
  3084. }
  3085. #endif /* NOSHOW */
  3086.  
  3087. #ifndef NOSPL
  3088. /* Evaluate an arithmetic expression. */
  3089. /* Code adapted from ev, by Howie Kaye of Columbia U & others. */
  3090.  
  3091. static int xerror;
  3092. static char *cp;
  3093. static long tokval;
  3094. static char curtok;
  3095. static long expval;
  3096.  
  3097. #define LONGBITS (8*sizeof (long))
  3098. #define NUMBER 'N'
  3099. #define EOT 'E'
  3100.  
  3101. /*
  3102.  Replacement for strchr() and index(), neither of which seem to be universal.
  3103. */
  3104.  
  3105. static char *
  3106. #ifdef CK_ANSIC
  3107. windex(char * s, char c)
  3108. #else
  3109. windex(s,c) char *s, c;
  3110. #endif /* CK_ANSIC */
  3111. /* windex */ {
  3112.     while (*s != NUL && *s != c) s++;
  3113.     if (*s == c) return(s); else return(NULL);
  3114. }
  3115.  
  3116. /*
  3117.  g e t t o k
  3118.  
  3119.  Returns the next token.  If token is a NUMBER, sets tokval appropriately.
  3120. */
  3121. static char
  3122. gettok() {
  3123.     while (isspace(*cp)) cp++ ;
  3124.     switch(*cp) {
  3125.       case '$':                /* ??? */
  3126.       case '+':                /* Add */
  3127.       case '-':                /* Subtract or Negate */
  3128.       case '@':                /* Greatest Common Divisor */
  3129.       case '*':                /* Multiply */
  3130.       case '/':                /* Divide */
  3131.       case '%':                /* Modulus */
  3132.       case '<':                /* Left shift */
  3133.       case '>':                /* Right shift */
  3134.       case '&':                /* And */
  3135.       case '|':                /* Or */
  3136.       case '#':                /* Exclusive Or */
  3137.       case '~':                /* Not */
  3138.       case '^':                /* Exponent */
  3139.       case '!':                /* Factorial */
  3140.       case '(':                /* Parens for grouping */
  3141.       case ')': return(*cp++);        /* operator, just return it */
  3142.       case '\n':
  3143.       case '\0': return(EOT);        /* end of line, return that */
  3144.     }
  3145.     if (isxdigit(*cp)) {        /* digit, must be a number */
  3146.     char tbuf[80],*tp;        /* buffer to accumulate number */
  3147.     int radix = 10;            /* default radix */
  3148.     for (tp=tbuf; isxdigit(*cp); cp++)
  3149.       *tp++ = isupper(*cp) ? tolower(*cp) : *cp;
  3150.     *tp = '\0';            /* end number */
  3151.     switch(isupper(*cp) ? tolower(*cp) : *cp) { /* examine break char */
  3152.       case 'h':
  3153.       case 'x': radix = 16; cp++; break; /* if radix signifier... */
  3154.       case 'o':
  3155.       case 'q': radix = 8; cp++; break;
  3156.       case 't': radix = 2; cp++; break;
  3157.     }
  3158.     for (tp=tbuf,tokval=0; *tp != '\0'; tp++)  {
  3159.         int dig;
  3160.         dig = *tp - '0';        /* convert number */
  3161.         if (dig > 10) dig -= 'a'-'0'-10;
  3162.         if (dig >= radix) {
  3163.         xerror = 1;
  3164.         if (cmdlvl == 0)
  3165.           printf("invalid digit '%c' in number\n",*tp);
  3166.         return(NUMBER);
  3167.         }
  3168.         tokval = radix*tokval + dig;
  3169.     }
  3170.     return(NUMBER);
  3171.     }
  3172.     if (cmdlvl == 0)
  3173.       printf("Invalid character '%c' in input\n",*cp);
  3174.     xerror = 1;
  3175.     cp++;
  3176.     return(gettok());
  3177. }
  3178.  
  3179. static long
  3180. #ifdef CK_ANSIC
  3181. expon(long x, long y)
  3182. #else
  3183. expon(x,y) long x,y;
  3184. #endif /* CK_ANSIC */
  3185. /* expon */ {
  3186.     long result = 1;
  3187.     int sign = 1;
  3188.     if (y < 0) return(0);
  3189.     if (x < 0) {
  3190.     x = -x;
  3191.     if (y & 1) sign = -1;
  3192.     }
  3193.     while (y != 0) {
  3194.     if (y & 1) result *= x;
  3195.     y >>= 1;
  3196.     if (y != 0) x *= x;
  3197.   }
  3198.   return(result * sign);
  3199. }
  3200.  
  3201. /*
  3202.  * factor ::= simple | simple ^ factor
  3203.  *
  3204.  */
  3205. _PROTOTYP( static VOID simple, (void) );
  3206.  
  3207. static VOID
  3208. factor() {
  3209.     long oldval;
  3210.     simple();
  3211.     if (curtok == '^') {
  3212.     oldval = expval;
  3213.     curtok = gettok();
  3214.     factor();
  3215.     expval = expon(oldval,expval);
  3216.     }
  3217. }
  3218.  
  3219. /*
  3220.  * termp ::= NULL | {*,/,%,&} factor termp
  3221.  *
  3222.  */
  3223. static VOID
  3224. termp() {
  3225.     while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == '&') {
  3226.     long oldval;
  3227.     char op;
  3228.     op = curtok;
  3229.     curtok = gettok();        /* skip past operator */
  3230.     oldval = expval;
  3231.     factor();
  3232.     switch(op) {
  3233.       case '*': expval = oldval * expval; break;
  3234.       case '/':
  3235.         if (expval == 0) expval = -1; /* don't divide by 0 */
  3236.         else expval = oldval / expval; break;
  3237.       case '%': expval = oldval % expval; break;
  3238.       case '&': expval = oldval & expval; break;
  3239.     }
  3240.     }
  3241. }
  3242.  
  3243. static long
  3244. #ifdef CK_ANSIC
  3245. fact(long x)
  3246. #else
  3247. fact(x) long x;
  3248. #endif /* CK_ANSIC */
  3249. /* fact */ {                /* factorial */
  3250.     long result = 1;
  3251.     while (x > 1)
  3252.       result *= x--;
  3253.     return(result);
  3254. }
  3255.  
  3256. /*
  3257.  * term ::= factor termp
  3258.  *
  3259.  */
  3260. static VOID
  3261. term() {
  3262.     factor();
  3263.     termp();
  3264. }
  3265.  
  3266. static long
  3267. #ifdef CK_ANSIC
  3268. gcd(long x, long y)
  3269. #else
  3270. gcd(x,y) long x,y;
  3271. #endif /* CK_ANSIC */
  3272. /* gcd */ {                /* Greatest Common Divisor */
  3273.     int nshift = 0;
  3274.     if (x < 0) x = -x;
  3275.     if (y < 0) y = -y;            /* validate arguments */
  3276.     if (x == 0 || y == 0) return(x + y);    /* this is bogus */
  3277.     
  3278.     while (!((x & 1) | (y & 1))) {    /* get rid of powers of 2 */
  3279.     nshift++;
  3280.     x >>= 1;
  3281.     y >>= 1;
  3282.     }
  3283.     while (x != 1 && y != 1 && x != 0 && y != 0) {
  3284.     while (!(x & 1)) x >>= 1;    /* eliminate unnecessary */
  3285.     while (!(y & 1)) y >>= 1;    /* powers of 2 */
  3286.     if (x < y) {            /* force x to be larger */
  3287.         long t;
  3288.         t = x;
  3289.         x = y;
  3290.         y = t;
  3291.     }
  3292.     x -= y;
  3293.     }
  3294.     if (x == 0 || y == 0) return((x + y) << nshift); /* gcd is non-zero one */
  3295.     else return((long) 1 << nshift);    /* else gcd is 1 */
  3296. }
  3297.  
  3298. /*
  3299.  * exprp ::= NULL | {+,-,|,...} term exprp
  3300.  *
  3301.  */
  3302. static VOID
  3303. exprp() {
  3304.     while (windex("+-|<>#@",curtok) != NULL) {
  3305.     long oldval;
  3306.     char op;
  3307.     op = curtok;
  3308.     curtok = gettok();        /* skip past operator */
  3309.     oldval = expval;
  3310.     term();
  3311.     switch(op) {
  3312.       case '+' : expval = oldval + expval; break;
  3313.       case '-' : expval = oldval - expval; break;
  3314.       case '|' : expval = oldval | expval; break;
  3315.       case '#' : expval = oldval ^ expval; break;
  3316.       case '@' : expval = gcd(oldval,expval); break;
  3317.       case '<' : expval = oldval << expval; break;
  3318.       case '>' : expval = oldval >> expval; break;
  3319.     }
  3320.     }
  3321. }
  3322.  
  3323. /*
  3324.  * expr ::= term exprp
  3325.  *
  3326.  */
  3327. static VOID
  3328. expr() {
  3329.     term();
  3330.     exprp();
  3331. }
  3332.  
  3333. static long
  3334. xparse() {
  3335.     curtok = gettok();
  3336.     expr();
  3337. #ifdef COMMENT
  3338.     if (curtok == '$') {
  3339.     curtok = gettok();
  3340.     if (curtok != NUMBER) {
  3341.         if (cmdlvl == 0) printf("illegal radix\n");
  3342.         return(0);
  3343.     }
  3344.     curtok = gettok();
  3345.     }
  3346. #endif /* COMMENT */
  3347.     if (curtok != EOT) {
  3348.     if (cmdlvl == 0)
  3349.       printf("extra characters after expression\n");
  3350.     xerror = 1;
  3351.     }
  3352.     return(expval);
  3353. }
  3354.  
  3355. char *
  3356. evala(s) char *s; {
  3357.     char *p;                /* Return pointer */
  3358.     long v;                /* Numeric value */
  3359.  
  3360.     xerror = 0;                /* Start out with no error */
  3361.     cp = s;                /* Make the argument global */
  3362.     v = xparse();            /* Parse the string */
  3363.     p = numbuf;                /* Convert long number to string */
  3364.     sprintf(p,"%ld",v);
  3365.     return(xerror ? "" : p);        /* Return empty string on error */
  3366. }
  3367.  
  3368. /*
  3369.  * simplest ::= NUMBER | ( expr )
  3370.  *
  3371.  */
  3372. static VOID
  3373. simplest() {
  3374.     if (curtok == NUMBER) expval = tokval;
  3375.     else if (curtok == '(') {
  3376.     curtok = gettok();        /* skip over paren */
  3377.     expr();
  3378.     if (curtok != ')') {
  3379.         if (cmdlvl == 0) printf("missing right parenthesis\n");
  3380.         xerror = 1;
  3381.     }
  3382.     }
  3383.     else {
  3384.     if (cmdlvl == 0) printf("operator unexpected\n");
  3385.     xerror = 1;
  3386.     }
  3387.     curtok = gettok();
  3388. }
  3389.  
  3390. /*
  3391.  * simpler ::= simplest | simplest !
  3392.  *
  3393.  */
  3394. static VOID
  3395. simpler() {
  3396.     simplest();
  3397.     if (curtok == '!') {
  3398.     curtok = gettok();
  3399.     expval = fact(expval);
  3400.     }
  3401. }
  3402.  
  3403. /*
  3404.  * simple ::= {-,~} simpler | simpler
  3405.  *
  3406.  */
  3407.  
  3408. static VOID
  3409. simple() {
  3410.     if (curtok == '-' || curtok == '~') {
  3411.     int op = curtok;
  3412.     curtok = gettok();        /* skip over - sign */
  3413.     simpler();            /* parse the factor again */
  3414.     expval = op == '-' ? -expval : ~expval;
  3415.     } else simpler();
  3416. }
  3417. #endif /* NOSPL */
  3418.  
  3419. #ifndef NOSPL
  3420. /*  D C L A R R A Y  --  Declare an array  */
  3421.  
  3422. int                    /* Declare an array of size n */
  3423. #ifdef CK_ANSIC
  3424. dclarray(char a, int n)
  3425. #else
  3426. dclarray(a,n) char a; int n;
  3427. #endif /* CK_ANSIC */
  3428. /* dclarray */ {
  3429.     char **p; int i, n2;
  3430.  
  3431.     if (a > 63 && a < 96) a += 32;    /* Convert to lowercase */
  3432.     if (a < 96 || a > 122) return(-1);    /* Verify name */
  3433.     a -= 96;                /* Convert name to number */
  3434.     if ((p = a_ptr[a]) != NULL) {    /* Delete old array of same name */
  3435.     n2 = a_dim[a];
  3436.     for (i = 0; i <= n2; i++)    /* First delete its elements */
  3437.       if (p[i]) free(p[i]);
  3438.     free(a_ptr[a]);            /* Then the element list */
  3439.     a_ptr[a] = (char **) NULL;    /* Remove pointer to element list */
  3440.     a_dim[a] = 0;            /* Set dimension at zero. */
  3441.     }
  3442.     if (n == 0) return(0);        /* If dimension 0, just deallocate. */
  3443.  
  3444.     p = (char **) malloc((n+1) * sizeof(char **)); /* Allocate for new array */
  3445.     if (p == NULL) return(-1);        /* Check */
  3446.     a_ptr[a] = p;            /* Save pointer to member list */
  3447.     a_dim[a] = n;            /* Save dimension */
  3448.     for (i = 0; i <= n; i++)        /* Initialize members to null */
  3449.       p[i] = NULL;
  3450.     return(0);
  3451. }
  3452.  
  3453. /*  A R R A Y N A M  --  Parse an array name  */
  3454.  
  3455. /*
  3456.   Call with pointer to string that starts with the array reference.
  3457.   String may begin with either \& or just &.
  3458.   On success,
  3459.     Returns letter ID (always lowercase) in argument c,
  3460.       which can also be accent grave (` = 96; '@' is converted to grave);
  3461.     Dimension or subscript in argument n;
  3462.     IMPORTANT: These arguments must be provided by the caller as addresses
  3463.     of ints (not chars), for example:
  3464.       char *s; int x, y;
  3465.       arraynam(s,&x,&y);
  3466.   On failure, returns a negative number, with args n and c set to zero.
  3467. */
  3468. int
  3469. arraynam(ss,c,n) char *ss; int *c; int *n; {
  3470.     int i, y, pp;
  3471.     char x;
  3472.     char *s, *p, *sx, *vnp;
  3473.     char vnbuf[VNAML+1];        /* On stack to allow for */
  3474.     char ssbuf[VNAML+1];        /* recursive calls... */
  3475.     char sxbuf[VNAML+1];
  3476.  
  3477.     *c = *n = 0;            /* Initialize return values */
  3478.     for (i = 0; i < (int)strlen(ss); i++) /* Check length */
  3479.       if (ss[i] == ']')
  3480.     break;
  3481.     if (i > VNAML) {
  3482.     printf("?Array reference too long - %s\n",ss);
  3483.     return(-9);
  3484.     }
  3485.     strncpy(vnbuf,ss,VNAML);
  3486.     vnp = vnbuf;
  3487.     if (vnbuf[0] == CMDQ && vnbuf[1] == '&') vnp++;
  3488.     if (*vnp != '&') {
  3489.     printf("?Not an array - %s\n",vnbuf);
  3490.     return(-9);
  3491.     }
  3492.     x = *(vnp + 1);            /* Fold case of array name */
  3493.     /* We don't use isupper & tolower here on purpose because these */
  3494.     /* would produce undesired effects with accented letters. */
  3495.     if (x > 63 && x < 91) x  = *(vnp +1) = x + 32;
  3496.     if ((x < 96) || (x > 122) || (*(vnp+2) != '[')) {
  3497.     printf("?Invalid format for array name - %s\n",vnbuf);
  3498.     return(-9);
  3499.     }
  3500.     *c = x;                /* Return the array name */
  3501.     s = vnp+3;                /* Get dimension */
  3502.     p = ssbuf;    
  3503.     pp = 1;                /* Bracket counter */
  3504.     for (i = 0; i < VNAML && *s != NUL; i++) { /* Copy up to ] */
  3505.     if (*s == '[') pp++;
  3506.     if (*s == ']' && --pp == 0) break;
  3507.     *p++ = *s++;
  3508.     }
  3509.     if (*s != ']') {
  3510.     printf("?No closing bracket on array dimension - %s\n",vnbuf);
  3511.     return(-9);
  3512.     }
  3513.     *p = NUL;                /* Terminate subscript with null */
  3514.     p = ssbuf;                /* Point to beginning of subscript */
  3515.     sx = sxbuf;                /* Where to put expanded subscript */
  3516.     y = VNAML-1;
  3517.     xxstring(p,&sx,&y);            /* Convert variables, etc. */
  3518.     if (!chknum(sxbuf)) {        /* Make sure it's all digits */
  3519.     printf("?Array dimension or subscript must be numeric - %s\n",sxbuf);
  3520.     return(-9);
  3521.     }
  3522.     if ((y = atoi(sxbuf)) < 0) {
  3523.         if (cmflgs == 0) printf("\n");
  3524.         printf("?Array dimension or subscript must be positive or zero - %s\n",
  3525.            sxbuf);
  3526.     return(-9);
  3527.     }
  3528.     *n = y;                /* Return the subscript or dimension */
  3529.     return(0);
  3530. }
  3531.  
  3532. int
  3533. chkarray(a,i) int a, i; {        /* Check if array is declared */
  3534.     int x;                /* and if subscript is in range */
  3535.     if (a == 64) a = 96;        /* Convert atsign to grave accent */
  3536.     x = a - 96;                /* Values must be in range 96-122 */
  3537.     if (x < 0 || x > 26) return(-2);    /* Not in range */
  3538.     if (a_ptr[x] == NULL) return(-1);    /* Not declared */
  3539.     if (i > a_dim[x]) return(-2);    /* Declared but out of range. */
  3540.     return(a_dim[x]);            /* All ok, return dimension */
  3541. }
  3542.  
  3543. char *
  3544. arrayval(a,i) int a, i; {        /* Return value of \&a[i] */
  3545.     int x; char **p;            /* (possibly NULL) */
  3546.  
  3547.     if (a == 64) a = 96;        /* Convert atsign to grave accent */
  3548.     x = a - 96;                /* Values must be in range 96-122 */
  3549.     if (x < 0 || x > 26) return(NULL);    /* Not in range */
  3550.     if ((p = a_ptr[x]) == NULL)        /* Array not declared */
  3551.       return(NULL);
  3552.     if (i > a_dim[x])            /* Subscript out of range. */
  3553.       return(NULL);
  3554.     return(p[i]);            /* All ok, return pointer to value. */
  3555. }
  3556. #endif /* NOSPL */
  3557.  
  3558. #ifndef NOSPL
  3559. /*  P A R S E V A R  --  Parse a variable name or array reference.  */
  3560. /*
  3561.  Call with:
  3562.    s  = pointer to candidate variable name or array reference.
  3563.    *c = address of integer in which to return variable ID.
  3564.    *i = address of integer in which to return array subscript.
  3565.  Returns:
  3566.    -2:  syntax error in variable name or array reference.
  3567.     1:  successful parse of a simple variable, with ID in c.
  3568.     2:  successful parse of an array reference, w/ID in c and subscript in i.
  3569. */
  3570. int
  3571. parsevar(s,c,i) char *s; int *c, *i; {
  3572.     char *p;
  3573.     int x,y,z;
  3574.  
  3575.     p = s;
  3576.     if (*s == CMDQ) s++;        /* Point after backslash */
  3577.  
  3578.     if (*s != '%' && *s != '&') {    /* Make sure it's % or & */
  3579.     printf("?Not a variable name - %s\n",p);
  3580.     return(-9);
  3581.     }
  3582.     if ((int)strlen(s) < 2) {
  3583.     printf("?Incomplete variable name - %s\n",p);
  3584.     return(-9);
  3585.     }
  3586.     if (*s == '%' && *(s+2) != '\0') {
  3587.     printf("?Only one character after '%%' in variable name, please\n");
  3588.     return(-9);
  3589.     }
  3590.     if (*s == '&' && *(s+2) != '[') {
  3591.     printf("?Array subscript expected - %s\n",p);
  3592.     return(-9);
  3593.     }
  3594.     if (*s == '%') {            /* Simple variable. */
  3595.     y = *(s+1);            /* Get variable ID letter/char */
  3596.     if (isupper(y)) y -= ('a'-'A');    /* Convert upper to lower case */
  3597.     *c = y;                /* Set the return values. */
  3598.     *i = -1;            /* No array subscript. */
  3599.     return(1);            /* Return 1 = simple variable */
  3600.     }
  3601.     if (*s == '&') {            /* Array reference. */
  3602.     if (arraynam(s,&x,&z) < 0) { /* Go parse it. */
  3603.         printf("?Invalid array reference - %s\n",p);
  3604.         return(-9);
  3605.     }
  3606.     if (chkarray(x,z) < 0) {    /* Check if declared, etc. */
  3607.         printf("?Array not declared or subscript out of range\n");
  3608.         return(-9);
  3609.     }
  3610.     *c = x;                /* Return array letter */
  3611.     *i = z;                /* and subscript. */
  3612.     return(2);
  3613.     }    
  3614.     return(-2);                /* None of the above. */
  3615. }
  3616.  
  3617. #define VALN 20
  3618.  
  3619. /* Get the numeric value of a variable */
  3620. /*
  3621.   Call with pointer to variable name, pointer to int for return value.
  3622.   Returns:
  3623.     0 on success with second arg containing the value.
  3624.    -1 on failure (bad variable syntax, variable not defined or not numeric).
  3625. */
  3626. int
  3627. varval(s,v) char *s; int *v; {
  3628.     char valbuf[VALN+1];        /* s is pointer to variable name */
  3629.     char *p;
  3630.     int y;
  3631.  
  3632.     p = valbuf;                /* Expand variable into valbuf. */
  3633.     y = VALN;
  3634.     if (xxstring(s,&p,&y) < 0) return(-1);
  3635.     p = valbuf;                /* Make sure value is numeric */
  3636.     if (!chknum(p)) return(-1);
  3637.     *v = atoi(p);            /* Convert numeric string to int */
  3638.     return(0);    
  3639. }
  3640.  
  3641. /* Increment or decrement a variable */
  3642. /* Returns -1 on failure, 0 on success, with 4th argument set to result */
  3643.  
  3644. int
  3645. incvar(s,x,z,r) char *s; int x, z, *r; { /* Increment a numeric variable */
  3646.     char valbuf[VALN+1];        /* s is pointer to variable name */
  3647.                     /* x is amount to increment by */
  3648.     int n;                /* z != 0 means add */
  3649.                     /* z = 0 means subtract */
  3650.  
  3651.     if (varval(s,&n) < 0)        /* Convert numeric string to int */
  3652.       return(-1);
  3653.     if (z)                /* Increment it by the given amount */
  3654.       n += x;
  3655.     else                /* or decrement as requested. */
  3656.       n -= x;
  3657.     sprintf(valbuf,"%d",n);        /* Convert back to numeric string */
  3658.     addmac(s,valbuf);            /* Replace old variable */
  3659.     *r = n;                /* Return the integer value */
  3660.     return(0);
  3661. }
  3662. #endif /* NOSPL */
  3663.  
  3664. /* Functions moved here from ckuusr.c to even out the module sizes... */
  3665.  
  3666. #ifndef NOSPL                /* Need xwords() function to break */
  3667. #define XWORDS                /* string up into words. */
  3668. #endif /* NOSPL */
  3669. #ifndef NODIAL
  3670. #ifndef XWORDS
  3671. #define XWORDS
  3672. #endif /* XWORDS */
  3673. #endif /* NODIAL */
  3674.  
  3675. #ifdef XWORDS
  3676. /*
  3677.   Breaks string s up into a list of up to max words.
  3678.   Pointers to each word go into the array list[].
  3679.   If list is NULL, then they are added to the macro table.
  3680. */
  3681.  
  3682. VOID
  3683. xwords(s,max,list) char *s; int max; char *list[]; {
  3684.     char *p;
  3685.     int b, k, y, z;
  3686. #ifndef NOSPL
  3687.     int macro;
  3688.     macro = (list == NULL);
  3689.     debug(F101,"xwords macro","",macro);
  3690. #endif /* NOSPL */
  3691.  
  3692.     p = s;                /* Pointer to beginning of string */
  3693.     b = 0;                /* Flag for outer brace removal */
  3694.     k = 0;                /* Flag for in-word */
  3695.     y = 0;                /* Brace nesting level */
  3696.     z = 0;                /* Argument counter, 0 thru max */
  3697.  
  3698.     while (1) {                /* Go thru argument list */
  3699.     if (!s || (*s == '\0')) {    /* No more characters? */
  3700.         if (k != 0) {
  3701.         if (z == max) break;    /* Only go up to max. */
  3702.         z++;            /* Count it. */
  3703. #ifndef NOSPL
  3704.         if (macro) {
  3705.             varnam[1] = z + '0'; /* Assign last argument */
  3706.             addmac(varnam,p);
  3707.         } else
  3708. #endif /* NOSPL */
  3709.           list[z] = p;
  3710.         break;            /* And get out. */
  3711.         } else break;
  3712.     } 
  3713.     if (k == 0 && (*s == SP || *s == HT)) { /* Eat leading blanks */
  3714.         s++;
  3715.         continue;
  3716.     } else if (*s == '{') {        /* An opening brace */
  3717.         if (k == 0 && y == 0) {    /* If leading brace */
  3718.         p = s+1;        /* point past it */
  3719.         b = 1;            /* and flag that we did this */
  3720.         }
  3721.         k = 1;            /* Flag that we're in a word */
  3722.         y++;            /* Count the brace. */
  3723.     } else if (*s == '}') {        /* A closing brace. */
  3724.         y--;            /* Count it. */
  3725.         if (y == 0 && b != 0) {    /* If it matches the leading brace */
  3726.         *s = SP;        /* change it to a space */
  3727.         b = 0;            /* and we're not in braces any more */
  3728.         } else if (y < 0) k = 1;    /* otherwise just start a new word. */
  3729.     } else if (*s != SP && *s != HT) { /* Nonspace means we're in a word */
  3730.         if (k == 0) p = s;        /* Mark the beginning */
  3731.         k = 1;            /* Set in-word flag */
  3732.     }
  3733.     /* If we're not inside a braced quantity, and we are in a word, and */
  3734.     /* we have hit whitespace, then we have an argument to assign. */
  3735.     if ((y < 1) && (k != 0) && (*s == SP || *s == HT)) { 
  3736.         *s = '\0';            /* terminate the arg with null */
  3737.         k = 0;            /* say we're not in a word any more */
  3738.         y = 0;            /* start braces off clean again */
  3739.         if (z == max) break;    /* Only go up to max. */
  3740.         z++;            /* count this arg */
  3741. #ifndef NOSPL
  3742.         if (macro) {
  3743.         varnam[1] = z + '0';    /* compute its name */
  3744.         addmac(varnam,p);    /* add it to the macro table */
  3745.         } else
  3746. #endif /* NOSPL */
  3747.           list[z] = p;
  3748.         p = s+1;
  3749.     }
  3750.     s++;                /* Point past this character */
  3751.     }
  3752.     if ((z == 0) && (y > 1)) {        /* Extra closing brace(s) at end */
  3753.     z++;
  3754. #ifndef NOSPL
  3755.     if (macro) {
  3756.         varnam[1] = z + '0';    /* compute its name */
  3757.         addmac(varnam,p);        /* Add rest of line to last arg */
  3758.     } else
  3759. #endif /* NOSPL */
  3760.       list[z] = p;
  3761.     }
  3762. #ifndef NOSPL
  3763.     if (macro) macargc[maclvl] = z + 1;    /* Set \v(argc) variable */
  3764. #endif /* NOSPL */
  3765.     return;
  3766. }
  3767. #endif /* XWORDS */
  3768.  
  3769. #ifndef NOSPL
  3770. /* D O D O  --  Do a macro */
  3771.  
  3772. /*
  3773.   Call with x = macro table index, s = pointer to arguments.
  3774.   Returns 0 on failure, 1 on success.
  3775. */
  3776.  
  3777. int
  3778. dodo(x,s) int x; char *s; {
  3779.     int y;
  3780.  
  3781.     debug(F101,"dodo maclvl","",maclvl);
  3782.     if (++maclvl > MACLEVEL) {        /* Make sure we have storage */
  3783.         debug(F101,"dodo maclvl too deep","",maclvl);
  3784.     --maclvl;
  3785.     printf("Macros nested too deeply\n");
  3786.     return(0);
  3787.     }
  3788.     macp[maclvl] = mactab[x].mval;    /* Point to the macro body */ 
  3789.     macx[maclvl] = mactab[x].mval;    /* Remember where the beginning is */
  3790.     debug(F111,"do macro",macp[maclvl],maclvl);
  3791.  
  3792.     cmdlvl++;                /* Entering a new command level */
  3793.     if (cmdlvl > CMDSTKL) {        /* Too many macros + TAKE files? */
  3794.         debug(F101,"dodo cmdlvl too deep","",cmdlvl);
  3795.     cmdlvl--;
  3796.     printf("?TAKE files and DO commands nested too deeply\n");
  3797.     return(0);
  3798.     }
  3799. #ifdef VMS
  3800.     conres();                /* So Ctrl-C, etc, will work. */
  3801. #endif /* VMS */
  3802.     ifcmd[cmdlvl] = 0;
  3803.     iftest[cmdlvl] = 0;
  3804.     count[cmdlvl] = count[cmdlvl-1]; /* Inherit COUNT from previous level */
  3805.     intime[cmdlvl] = intime[cmdlvl-1];    /* Inherit previous INPUT TIMEOUT */
  3806.     inpcas[cmdlvl] = inpcas[cmdlvl-1];    /*   and INPUT CASE */
  3807.     takerr[cmdlvl] = takerr[cmdlvl-1];    /*   and TAKE ERROR */
  3808.     merror[cmdlvl] = merror[cmdlvl-1];    /*   and MACRO ERROR */
  3809.     cmdstk[cmdlvl].src = CMD_MD;    /* Say we're in a macro */
  3810.     cmdstk[cmdlvl].lvl = maclvl;    /* and remember the macro level */
  3811.     mrval[maclvl] = NULL;        /* Initialize return value */
  3812.  
  3813.     debug(F110,"do macro",mactab[x].kwd,0);
  3814.  
  3815. /* Clear old %0..%9 arguments */
  3816.  
  3817.     addmac("%0",mactab[x].kwd);        /* Define %0 = name of macro */
  3818.     varnam[0] = '%';
  3819.     varnam[2] = '\0';
  3820.     for (y = 1; y < 10; y++) {        /* Clear args %1..%9 */
  3821.     varnam[1] = y + '0';
  3822.     delmac(varnam);
  3823.     }    
  3824.  
  3825. /* Assign the new args one word per arg, allowing braces to group words */
  3826.  
  3827.     xwords(s,9,NULL);
  3828.     return(1);
  3829. }
  3830.  
  3831. /* Insert "literal" quote around each comma-separated command to prevent */
  3832. /* its premature expansion.  Only do this if object command is surrounded */
  3833. /* by braces. */
  3834.  
  3835. static char* flit = "\\flit(";
  3836.  
  3837. int
  3838. litcmd(src,dest) char **src, **dest; {
  3839.     int bc = 0, pp = 0;
  3840.     char *s, *lp, *ss;
  3841.  
  3842.     s = *src;
  3843.     lp = *dest;
  3844.  
  3845.     while (*s == SP) s++;        /* strip extra leading spaces */
  3846.     if (*s == '{') {
  3847.  
  3848.         pp = 0;                /* paren counter */
  3849.     bc = 1;                /* count leading brace */
  3850.     *lp++ = *s++;            /* copy it */
  3851.     while (*s == SP) s++;        /* strip interior leading spaces */
  3852.     ss = flit;            /* point to "\flit(" */
  3853.     while (*lp++ = *ss++) ;        /* copy it */
  3854.     lp--;                /* back up over null */
  3855.     while (*s) {            /* go thru rest of text */
  3856.         ss = flit;            /* point back to start of "\flit(" */
  3857.         if (*s == '{') bc++;    /* count brackets */
  3858.         if (*s == '(') pp++;    /* and parens */
  3859.         if (*s == ')') pp--;
  3860.         if (*s == '}') {        /* Closing brace. */
  3861.         if (--bc == 0) {    /* Final one? */
  3862.             *lp++ = ')';    /* Add closing paren for "\flit()" */
  3863.             *lp++ = *s++;
  3864.             break;
  3865.         }
  3866.         }
  3867.         if (*s == ',' && pp == 0) {    /* comma not inside of parens */
  3868.         *lp++ = ')';        /* closing ) of \flit( */
  3869.         *lp++ = ',';        /* insert the comma */
  3870.         while (*lp++ = *ss++) ;    /* start new "\flit(" */
  3871.         lp--;            /* back up over null */
  3872.         s++;            /* skip over comma in source string */
  3873.         while (*s++ == SP);    /* eat leading spaces again. */
  3874.         s--;            /* back up over nonspace */
  3875.         continue;
  3876.         }
  3877.             *lp++ = *s++;        /* Copy anything but comma here. */
  3878.         }
  3879.     *lp = NUL;
  3880.     } else {                /* No brackets around, */
  3881.     while (*lp++ = *s++) ;        /* just copy. */
  3882.     lp--;
  3883.     }
  3884.     *src = s;
  3885.     *dest = lp;
  3886.     if (bc) return(-1);
  3887.     else return(0);
  3888. }
  3889. #endif /* NOSPL */
  3890.  
  3891. int
  3892. docd() {                /* Do the CD command */
  3893.     int x;
  3894.     char *s;
  3895.  
  3896. #ifdef GEMDOS
  3897.     if ((x = cmdir("Name of local directory, or carriage return",homdir,&s,
  3898.            NULL)) < 0 )
  3899. #else
  3900.     if ((x = cmdir("Name of local directory, or carriage return",homdir,&s,
  3901.            xxstring)) < 0 )
  3902. #endif /* GEMDOS */
  3903.       return(x);
  3904.     if (x == 2) {
  3905.     printf("?Wildcards not allowed in directory name\n");
  3906.     return(-9);
  3907.     }
  3908.     strcpy(line,s);            /* Make a safe copy */
  3909.     s = line;
  3910.     if ((x = cmcfm()) < 0)        /* Get confirmation */
  3911.       return(x);
  3912.     if (! zchdir(s)) {
  3913.     cwdf = 0;
  3914.     perror(s);
  3915.     } else cwdf = 1;
  3916. #ifdef OS2
  3917.     printf("%s\n", zgtdir());
  3918. #else /* Not OS2 */
  3919. #ifndef MAC
  3920.     zsyscmd(PWDCMD);            /* assume this works... */
  3921. #endif /* MAC */
  3922. #endif /* OS2 */
  3923.     return(cwdf);
  3924. }
  3925.  
  3926. VOID
  3927. fixcmd() {            /* Fix command parser after interruption */
  3928.     dostop();            /* Back to top level (also calls conint()). */
  3929.     bgchk();            /* Check background status */
  3930.     if (*psave) {        /* If old prompt saved, */
  3931.     cmsetp(psave);        /* restore it. */
  3932.     *psave = NUL;
  3933.     }
  3934.     success = 0;        /* Tell parser last command failed */
  3935. }
  3936.  
  3937. VOID
  3938. prtopt(s) char *s; {            /* Print an option */
  3939.     static int x = 0;            /* (used by SHOW VER) */
  3940.     int y;                /* Does word wrap. */
  3941.     if (!s) { x = 0; return; }        /* Call with null pointer to */
  3942.     y = (int)strlen(s);            /* reset horizontal position. */
  3943.     x += y;
  3944.     if (x > 79) {
  3945.     printf("\n%s",s);
  3946.     x = y;
  3947.     } else printf("%s",s);
  3948. }
  3949.  
  3950. #endif /* NOICP */
  3951.